Perl 6: nextsame и его родственники

Возможно, вам знаком способ, которым ключевое слово super в языке Java позволяет передавать управление методу (или конструктору) базового класса. В Perl 6 есть нечто похожее. Но в мире с множественной наследуемостью и миксинами нет смысла называть эту функцию super. Поэтому она называется nextsame.Пример: class A { method sing { say «а после умерла.»; } }

class B is A { method sing { say («зимой и летом стройная,» xx 4).join (» »); nextsame; } }

class C is B { method sing { say «в лесу родилась ёлочка,»; say «в лесу она росла.»; nextsame; } } И после вызова C.new.sing, наша иерархия классов выдаст следующее: в лесу родилась ёлочка, в лесу она росла.зимой и летом стройная, а после умерла.

Обратите внимание, как вызов проходит от C.sing через B.sing к A.sing. Эти переходы обеспечиваются вызовами nextsame. Похоже на работу super в Java.

Но nextsame пригодится не только для вызовов по цепочке наследования. Вот пример без ООП:

sub bray { say «а у барана — лексус.»; }

# Oh right, forgot to add the first line of the song… &bray.wrap ({ say «У нашей Мэри был баран,»; nextsame; });

bray (); # У нашей Мэри был баран, #, а у барана — лексус. Поэтому nextsame не назвали super: он не всегда обращается к базовому классу. Вместо этого происходит нечто более общего порядка. Что же именно?

Каждый раз при вызове некоторая часть языка заботится о том, что вызов приходит в нужную процедуру. Эта часть зовётся диспетчером. Диспетчер убеждается, что в следующем множественном вызове принимает участие нужная процедура:

multi foo ($x) { say «Любой аргумент » } multi foo (Int $x) { say «Аргумент Int » }

foo (42) # Аргумент Int И использование nextsame во втором foo приведёт к вызову первого.

В Perl 6 диспетчеры повсюду.

06c5f66f3398413da16d82704fe7c4cf.jpg

Они работают при вызовах методов, чтобы те могли передать вызов по цепочке наследования. Они во wrapped-процедурах, чтобы код, делающий «обёртывание», мог вызвать код, который он обёртывает. И они участвуют во множественных вызовах — чтобы разные варианты одной функции могли ссылаться друг на друга. Принцип один.

nextsame — способ пообщаться с вашим соседом-диспетчером. Диспетчер обращается к следующему кандидату с такой же сигнатурой.

Его можно использовать и в миксинах:

class A { method foo { «Оба-на» } }

role LogFoo { method foo { note ».foo вызвали»; nextsame; } }

my $logged_A = A.new but LogFoo;

say $logged_A.foo; # .foo вызвали # Оба-на Особой новизны в таком использовании nextsame нет. Это ещё один пример передачи управления по цепочке наследования. Миксин в роли LogFoo вместе с but приводит к тому, что создаётся ещё один анонимный подкласс, который тоже выполняет роль LogFoo. Поэтому в данном случае миксин nextsame сводится к nextsame для наследования.

В итоге, nextsame работает везде, где вы ожидаете, и так, как ожидаете. Он передаёт управление следующей такой же штуке.

И у него есть близкие родственники:

nextsame передать управление с теми же аргументами, не возвращаться callsame передать управление с теми же аргументами, и вернуться

nextwith ($p1, $p2, …) передать управление с заданными аргументами, не возвращаться

callwith ($p1, $p2, …) передать управление с заданными аргументами, вернуться Все они обычно могут быть использованы в тех же ситуациях, в которых работает nextsame.

© Habrahabr.ru