Re-dispatch — callsame, nextsame & friends
FullFrom inside a routine, call the next matching candidate — a parent method or the next multi.
When several routines could handle a call — an overriding method and the parent it shadows, or a chain of multi candidates — you often want to run the next one down from inside the current one. The re-dispatch routines do exactly that: callsame and callwith run the next candidate and return its result to you; nextsame and nextwith hand control off to it and never come back. same reuses the current arguments; with supplies new ones.
| reuse current args | give new args | |
|---|---|---|
| return here | callsame | callwith |
| tail-call | nextsame | nextwith |
Extending a parent method #
Inside an override, callsame runs the method it replaced — here the Animal version — so a subclass can add to behaviour instead of copying it.
class Animal { method describe { "an animal" } }
class Dog is Animal {
method describe { callsame() ~ " that barks" }
}
say Dog.new.describe;
an animal that barksThe chain follows the full inheritance order, so each level can wrap the one below:
class A { method m { "A" } }
class B is A { method m { callsame() ~ "B" } }
class C is B { method m { callsame() ~ "C" } }
say C.m;
ABCDeferring to the next multi #
Among multi candidates, callsame runs the next-most-specific one. Here the Int candidate decorates the result of the generic Any candidate.
multi describe(Int $n) { "number: " ~ callsame() }
multi describe(Any $x) { "value $x" }
say describe(5);
number: value 5return vs. tail-call #
The call* forms return the next candidate's result so you can keep working with it; the next* forms transfer control, so any code after them never runs.
multi f(Int $x) { my $r = callsame; "[$r]" } # returns, then wraps
multi g(Int $x) { nextsame; "NEVER" } # hands off, this line is dead
multi f(Any $x) { "base" }
multi g(Any $x) { "base" }
say f(3);
say g(3);
[base]
basePassing different arguments #
callwith/nextwith re-dispatch with a fresh argument list — and samewith restarts the whole dispatch from the top with new arguments, the idiomatic way to recurse across multis.
multi fac(0) { 1 }
multi fac(Int $n) { $n * samewith($n - 1) }
say fac(5);
120Notes #
callsame/nextsametake no arguments (they reuse the current@_);callwith/nextwithtake the new argument list.- These work in method overrides (Inheritance) and in
multichains (Multi dispatch) alike — same routines, same rules. samewithdiffers fromcallwith:callwithruns the next candidate, whilesamewithre-runs dispatch from scratch — so it can land back on the current candidate, which is what makes recursive multis terminate.- A wrapped routine (
&r.wrap({ … callsame() … })) uses the same mechanism: the wrapper callscallsameto invoke the original.