Whatisthe_intended_valueof&?ROUTINE?
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)
回答
该&?ROUTINE符号应计算为表示最近的词法封闭例程的对象 - 即最近的 type 封闭声明Routine。这包括Sub和Method。此外,鉴于这些原则上都是闭包,它应该评估例程的正确闭包克隆。
因此,正确的实现将产生:
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
因此,当前的乐堂在许多情况下都犯了这个错误。尽管在编译器上做了大量工作,我还是不太清楚它在这里做什么;我确实知道,当我开始&?ROUTINE在我正在开发的新编译器前端添加支持时,我不会复制当前的实现!
回答
根据@Larry 的规范[1]:
&?ROUTINE始终是词法最里面的别名Routine(其可以是一个Sub,Method或Submethod)...您可以通过调用获取当前例程名称
&?ROUTINE.name。在任何 [例程] 声明之外,此调用返回失败。请注意,
&?ROUTINE指的是当前单个 [例程],即使它已声明multi。要以给定的短名称重新调度到整个套件,只需使用命名形式调用 proto,因为没有匿名multis。
脚注
[1] “@Larry”是/曾经是不断发展的事实上的 Raku 设计团队的历史速记。“规格”是/曾经是不断发展的设计的历史简写。以上引用来自 S06 部分&?ROUTINE 对象