📜 ⬆️ ⬇️

Perl 6: nextsame and its relatives

You may know the way in which the super keyword in the Java language allows you to transfer control to a method (or constructor) of a base class. Perl 6 has something similar. But in a world with multiple heritability and mixins, it makes no sense to call this function super. Therefore, it is called nextsame.
Example:

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; } } 


And after calling C.new.sing, our class hierarchy will return the following:

The Forest Raised a Christmas Tree,
in the forest she grew up.
winter and summer slim
and after she died.
')
Notice how the call goes from C.sing through B.sing to A.sing. These transitions are provided by nextsame calls. Looks like a super job in java.

But nextsame is useful not only for calls on the inheritance chain. Here is an example without OOP:

 sub bray { say "   - ."; } # Oh right, forgot to add the first line of the song... &bray.wrap( { say "    ,"; nextsame; } ); bray(); #     , #    - . 


Therefore, nextsame was not called super: it does not always refer to the base class. Instead, something more general happens. What exactly?

Each time you call, some part of the language ensures that the call comes in the correct procedure. This part is called the dispatcher. The dispatcher is satisfied that the desired procedure is involved in the following multiple call:

 multi foo( $x) { say "  " } multi foo(Int $x) { say " Int " } foo(42) #  Int 


And using nextsame in the second foo will call the first.

In Perl 6, dispatchers are everywhere.



They work on method calls so that they can pass the call along the inheritance chain. They are in wrapped procedures so that the code that does the wrapping can call the code it wraps. And they participate in multiple calls - so that different versions of the same function can refer to each other. Principle one.

nextsame is a way to chat with your dispatcher neighbor. The dispatcher addresses the next candidate with the same signature.

It can be used in mixins:

 class A { method foo { "-" } } role LogFoo { method foo { note ".foo "; nextsame; } } my $logged_A = A.new but LogFoo; say $logged_A.foo; # .foo  # - 


There is no particular novelty in this use of nextsame. This is another example of passing control along an inheritance chain. Mixin in the role of LogFoo along with but leads to the fact that another anonymous subclass is created, which also plays the role of LogFoo. Therefore, in this case, the nextsame mixin is reduced to nextsame for inheritance.

As a result, nextsame works wherever you expect, and in the way you expect. He hands over control to the next one.

And he has close relatives:

 nextsame      ,   callsame      ,   nextwith($p1, $p2, ...)     ,   callwith($p1, $p2, ...)     ,  


All of them can usually be used in the same situations in which nextsame works.

Source: https://habr.com/ru/post/254787/


All Articles