Maybe you’re familiar with the way the keyword super
in Java allows you to delegate to the method (or constructor) of a base class. Perl 6 has something similar… but in a world with multiple inheritance and mixins it makes less sense to call it super
. So it’s called nextsame
. Here’s an example of its use:
class A { method sing { say "life is but a dream."; } } class B is A { method sing { say ("merrily," xx 4).join(" "); nextsame; } } class C is B { method sing { say "row, row, row your boat,"; say "gently down the stream."; nextsame; } }
Now, when we call C.new.sing
, our class hierarchy will output this:
row, row, row your boat, gently down the stream. merrily, merrily, merrily, merrily, life is but a dream.
You’ll note how the call finds its way from C.sing
via B.sing
over to A.sing
. Those transitions are (of course) mediated by the nextsame
calls. You’ll note the similarity to, for example, Java’s super
.
But calling along the inheritance chain is not the only place where nextsame
proves useful. Here’s an example not involving object orientation:
sub bray { say "EE-I-EE-I-OO."; } # Oh right, forgot to add the first line of the song... &bray.wrap( { say "Old MacDonald had a farm,"; nextsame; } ); bray(); # Old MacDonald had a farm, # EE-I-EE-I-OO.
So that’s another reason nextsame
is not called super
: it’s not necessarily related to the base class, because there might not be a base class. Instead, there’s some more general phenomenon involved. What might that be?
Every time we do a call to something, there’s a part of the language runtime making sure that the call ends up in the right routine. Such a part is called a dispatcher. A dispatcher makes sure that the following multi call ends up in the appropriate routine:
multi foo( $x) { say "Any argument" } multi foo(Int $x) { say "Int argument" } foo(42) # Int argument
(And a nextsame
in the second multi foo
would re-dispatch to the first. But that doesn’t work in Rakudo yet.)
Dispatchers are everywhere in Perl 6. They’re involved in method calls, so that a method can defer along the inheritance chain, as we did in the beginning of the post. They’re in wrapped routines, so that the code doing the wrapping can call into the code being wrapped. And they participate in multi dispatch, so that multi variants can defer to each other. It’s all the same principle, but in different guises.
And nextsame
is just a way to talk directly to your friendly neighborhood dispatcher. By the way, the keyword is called nextsame because it instructs the dispatcher to defer to the next candidate with the same signature. There are variants, as you’ll see below.
You can use nextsame
in mixins, too:
class A { method foo { "OH HAI" } } role LogFoo { method foo { note ".foo was called"; nextsame; } } my $logged_A = A.new but LogFoo; say $logged_A.foo; # .foo was called # OH HAI
I like this way to use mixins to inject behavior. I once wrote a post about it, and jnthn has written a Perl 6 module that exploits it.
Though pretty cool, this use of nextsame
isn’t really anything new; in fact it’s just another example of the defer-along-the-OO-callchain dispatcher. That’s because mixing in the role LogFoo
with but
causes an anonymous subclass to be created, one that also does LogFoo
. So role mixin nextsame
boils down to just inheritance nextsame
. (But we don’t need to actually grok that to use it, and it still feels slightly magical and very nice to use.)
In summary, nextsame
works in a lot of places you’d expect it to work, and it works the way you expect it to. It defers to the next thing.
Oh, and nextsame
has three closely related cousin keywords:
nextsame Defer with the same arguments, don't return callsame Defer with the same arguments, then return nextwith($p1, $p2, ...) Defer with these arguments, don't return callwith($p1, $p2, ...) Defer with these arguments, then return
Naturally, the other three can be used in the same situations nextsame
can.