&?ROUTINE 的 _intended_ 值是多少?

问题描述

Raku 的 Rakudo 实现跟踪了关于(非常有用!)&?ROUTINE 变量没有提供正确值(例如,#17682362)的多个问题,所以我意识到它没有表现非常正确。但我试图了解它的预期行为是什么——这似乎是修复该行为的重要第一步。

使用 Rakudo v2021.06 运行此代码会产生注释中注明的输出。此输出的哪些部分是正确的,哪些代表错误?

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 

relevant docs 说 &?ROUTINE 返回“一个 Sub 的实例”,这使得上面的所有内容听起来都应该是 'foo'。另一方面,方法是例程,所以我有点倾向于认为最后两个(匿名方法和命名方法)应该是'foo'。我也不确定所有的 '' 和 "" 值是否都代表错误,或者是否有一个原则在起作用,导致某些(或全部?)这些预期行为。

(我还使用 use soft 编译指示测试了上述代码,以确保内联不会产生我可以使用该编译指示修复的影响;它对输出没有影响)

解决方法

&?ROUTINE 符号的计算结果应该是表示最近的词法封闭例程的对象 - 即最近的 Routine 类型的封闭声明。这包括 SubMethod。此外,鉴于这些原则上都是闭包,它应该评估为例程的正确闭包克隆。

因此正确的实现会产生:

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(可能是 SubMethodSubmethod)的别名...>

您可以通过调用 &?ROUTINE.name 获取当前例程名称。在任何 [例程] 声明之外,此调用返回失败。

请注意,&?ROUTINE 指的是当前的单个 [例程],即使它声明为 multi。要以给定的短名称重新调度到整个套件,只需使用命名形式调用 proto,因为没有匿名 multi

脚注

[1]“@Larry”是/曾经是不断发展的事实上的 Raku 设计团队的历史速记。 “规格”是/曾经是不断发展的设计的历史简写。以上引述来自 S06 部分 The &?ROUTINE object

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...