The Rakudo implementation of Raku tracks multiple issues about the (very useful!) &?ROUTINE variable not providing the correct value (e.g., #1768 and 2362), so I realize that it's not behaving quite correctly. But I'm trying to understand what it's intended behavior is – which seems like an essential first step in fixing that behavior.
Running this code with Rakudo v2021.06 produces the output noted in the comments. Which parts of this output are correct, and which represent bugs?
sub foo {
note '## ifs:';
do if True { say &?ROUTINE.name } # OUTPUT: «foo»
if True { say &?ROUTINE.name } # OUTPUT: «<unit>»
note '## ifs w/ topic:';
do if True -> $a { say $a; say &?ROUTINE.name } # OUTPUT: «True», # OUTPUT«""»
if True -> $a { say $a; say &?ROUTINE.name } # OUTPUT: «True», # OUTPUT«foo»
note '## fors:';
for 1 { say &?ROUTINE.name } # OUTPUT: «foo»
say &?ROUTINE.name for 1; # OUTPUT: «""»
note '## methods:';
42.&{ say &?ROUTINE.name } # OUTPUT: «foo»
my method m($a:) { say &?ROUTINE.name }
42.&m; # OUTPUT: «m»
}
foo
The relevant docs say that &?ROUTINE returns "an instance of Sub", which makes it sound like all of the above should be 'foo'. On the other hand, a Method is a Routine, so I'm somewhat inclined to think that the last two (an anonymous method and a named method) should not be 'foo'. I'm also unsure whether all the '' and "" values represent bugs, or if there's a principle at work that makes some (or all?) of those intended behavior.
(I also tested the above code with the use soft
pragma to make sure that inlining wasn't having an effect that I could fix with that pragma; it had no effect on the output)
The &?ROUTINE
symbol should evaluate to an object representing the nearest lexically enclosing routine - that is, the nearest enclosing declaration of type Routine
. This includes both Sub
and Method
. Furthermore, given these are all in principle closures, it should evaluate to the correct closure clone of the routine.
Thus a correct implementation would produce:
sub foo {
note '## ifs:';
do if True { say &?ROUTINE.name } # OUTPUT: «foo»
if True { say &?ROUTINE.name } # OUTPUT: «foo»
note '## ifs w/ topic:';
do if True -> $a { say $a; say &?ROUTINE.name } # OUTPUT: «True», # OUTPUT«foo»
if True -> $a { say $a; say &?ROUTINE.name } # OUTPUT: «True», # OUTPUT«foo»
note '## fors:';
for 1 { say &?ROUTINE.name } # OUTPUT: «foo»
say &?ROUTINE.name for 1; # OUTPUT: «foo»
note '## methods:';
42.&{ say &?ROUTINE.name } # OUTPUT: «foo»
my method m($a:) { say &?ROUTINE.name }
42.&m; # OUTPUT: «m»
}
foo
Current Rakudo is thus getting this wrong in a number of cases. Despite having worked extensively on the compiler, I don't have a good guess what it's doing here; I do know that I won't be copying the current implementation when I get to adding &?ROUTINE
support in the new compiler frontend that I'm working on!
Per @Larry's spec[1]:
&?ROUTINE
is always an alias for the lexically innermostRoutine
(which may be aSub
,Method
, orSubmethod
) ...You can get the current routine name by calling
&?ROUTINE.name
. Outside of any [routine] declaration, this call returns failure.Note that
&?ROUTINE
refers to the current single [routine], even if it is declaredmulti
. To redispatch to the entire suite under a given short name, just use the named form to call the proto, since there are no anonymousmulti
s.
[1] "@Larry" is/was historical shorthand for the evolving de facto Raku design team. "spec" is/was historical shorthand for the evolving design. The above quotes are from S06 section The &?ROUTINE object
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With