Мультиметод для Прокси - PullRequest
       13

Мультиметод для Прокси

5 голосов
/ 18 октября 2019

Можно ли использовать multidispatch для метода store при использовании Proxy? В следующем минимальном примере код вызывается при сохранении Int

my $foo := do {
  my $bar = 1;
  Proxy.new:
    :FETCH( method { return $bar} ),
    :STORE( method (Int $i) { $bar = $i } )
}

say $foo;   # 1
$foo = 2;
say $foo;   # 2
$foo = "3"; # error, need to pass an Int

Но я бы хотел по-разному обрабатывать STORE, если дано, скажем, Str. Обход, который я нашел (кроме мега-метода с given / where, заключается в создании multi sub внутри блока и возврате подпрограммы (потому что на multi method нельзя ссылатьсяс &foo) с фиктивным первым параметром:

my $foo := do {
  my $bar = 1;
  Proxy.new:
    :FETCH( method { return $bar} ),
    :STORE( 
      do { 
        multi sub xyzzy ($, Int $i) { $bar = $i }
        multi sub xyzzy ($, Str $i) { $bar = +$i + 1}
        &xyzzy
      }
    )
}

say $foo;   # 1
$foo = 2;   
say $foo;   # 2
$foo = "3"; 
say $foo;   # 4

Есть ли лучший способ сделать это (в основном для ясности кода, используя method, потому что sub чувствует себя ... вводящим в заблуждение)?

1 Ответ

6 голосов
/ 19 октября 2019

Что касается введения в заблуждение: значения FETCH и STORE указывают Callables, что может быть либо method, либо sub.

Возвращаясь к вопросу,нет прямого способа сделать это, но есть лучший косвенный способ, который может быть более ясным. Вы можете сделать это, установив сначала multi sub, а затем передав proto в качестве параметра:

proto sub store(|) {*}
multi sub store(\self, Int) { say "Int" }
multi sub store(\self, Str) { say "Str" }

my $a := Proxy.new(
  FETCH => -> $ { 42 },
  STORE => &store,
);

say $a;     # 42
$a = 42;    # Int
$a = "foo"; # Str

И если вы хотите сделать код короче, но, возможно, менее понятным, вы можетеизбавьтесь от proto (потому что он будет сгенерирован для вас автоматически) и sub в multi (потому что вы можете):

multi store(\self, Int) { say "Int" }
multi store(\self, Str) { say "Str" }

my $a := Proxy.new(
  FETCH => -> $ { 42 },
  STORE => &store,
);

say $a;     # 42
$a = 42;    # Int
$a = "foo"; # Str
...