重新绑定的规则是什么?

cod*_*ons 7 immutability rakudo lexical-scope variable-binding raku

[注意:我根据旧版本的 Rakudo 问这个问题。正如已接受的答案中所解释的,令人困惑的输出是 Rakudo bug 的结果,现已解决。我留下了下面 Q 的原始版本以供历史参考。]

\n

Raku 有时会禁止重新绑定;以下两行

\n
sub f($a) { $a := 42 }\nmy \\var = \'foo\'; var := \'not-foo\';\n
Run Code Online (Sandbox Code Playgroud)\n

产生编译时错误:

\n
===SORRY!=== Error while compiling \nCannot use bind operator with this left-hand side\n
Run Code Online (Sandbox Code Playgroud)\n

然而,Raku 允许在很多很多情况下重新绑定 \xe2\x80\x93 ,包括许多让我大吃一惊的情况。以下所有内容都成功重新绑定;每个say输出not-foo

\n
sub f($a) { $a := 42 }\nmy \\var = \'foo\'; var := \'not-foo\';\n
Run Code Online (Sandbox Code Playgroud)\n

因此,目前看来,只要满足以下任一条件,任何名称都可以重新绑定,无论是否有印记:

\n
    \n
  1. 该名称具有任何显式类型约束(包括或符号Any施加的类型约束),或者@%
  2. \n
  3. 重新绑定使用限定名称。
  4. \n
\n

目前,声明的变量和参数都会发生这种重新绑定,并且包括不是rw或 的参数copy。正如最后一个示例所示,它甚至允许以(似乎?)违反词法范围的方式重新绑定。(该示例基于带有注释的Roast 测试-- legal?,这表明我可能至少不是唯一一个发现这种行为令人惊讶的人!尽管该测试is dynamic在某些情况下重新绑定了变量 \xe2\x80\x93方式,上面的行为更令人惊讶)。

\n

据我所知,唯一不能使用这些方法之一重新绑定的名称是那些声明为constant.

\n

那么四个问题:

\n
    \n
  1. 我是否正确描述了当前的行为?[编辑:也就是说,我上面列出的两个规则是否正确描述了当前行为,或者正确的描述是否需要其他/附加规则?]
  2. \n
  3. 这种行为是否正确/有意/符合规范?(尽管存在S03 结合,但我发现重新结合的情况非常少)。
  4. \n
  5. 如果这种行为不是故意的,那么重新绑定的规则应该是什么?
  6. \n
  7. 有没有办法告诉 Raku“不要将此名称重新绑定到新值,不是真的”?
  8. \n
\n

(这个问题取代了我之前的问题,在我意识到重新绑定名称是多么容易之前我就问过这个问题;我将关闭它以支持这个问题。另一个相关问题:禁止无符号变量是否有目的或好处来自重新绑定? ,其中讨论了基于无符号变量不能的假设的一些设计权衡重新绑定的

\n

cod*_*ons 0

我在问题中询问的不一致行为是 Rakudo bug \xe2\x80\x93 Rakudo 的结果,Rakudo 允许在某些不应该的情况下重新绑定。此错误已在Rakudo/Rakudo#4536中解决。

\n

经过此决议后,重新绑定的规则为:

\n
    \n
  • 无符号“变量”无法反弹(并且无法重新分配,因此它们不是真正的“变量”)
  • \n
  • 带有印记的变量通常可以反弹,但以下例外。
  • \n
  • 如果 sigiled 变量是Signature的一部分,则它不能被反弹,除非它被声明为可通过is copyis rwTraits重新绑定。\n
      \n
    • 这适用于函数的签名(因此sub f($a) { $a := 42 }是非法的)
    • \n
    • 它还适用于作为变量声明的一部分进行解构的签名:=。例如,在 中my ($var1, $var2) := (\'foo\', \'bar\'),右侧是签名,因此$var1$var2不能反弹。
    • \n
    \n
  • \n
\n

应用这些规则意味着现在禁止以下所有重新绑定(在提出问题时允许):

\n
my Any \\a = \'foo\';\nsay a := \'not-foo\';\n\nsub fn1(Any \\a) { a := \'not-foo\';  say a  }\nfn1 \'foo\';\nsub fn2(Any $b) { $b := \'not-foo\'; say $b }\nfn2 \'foo\';\nsub fn3(@c) {  @c := (\'not-foo\', \'not-foo\'); say @c }\nfn3 (\'foo\', \'foo\');\nsub fn4(+@d) { @d := (\'not-foo\', \'not-foo\'); say @d }\nfn4 (\'foo\', \'foo\');\nsub fn5(@d is raw) { @d := (\'not-foo\', \'not-foo\'); say @d }\nfn5 (\'foo\', \'foo\');\n\nmy ($one-foo, $two-foo) := (\'foo\', \'foo\');\n$one-foo := \'not-foo\';\nsay $one-foo;\n
Run Code Online (Sandbox Code Playgroud)\n

相反,应用这些规则意味着问题中显示的一些其他重新绑定是(正确)允许的:

\n
my Any $b := \'foo\';\nsay $b := \'not-foo\';\nmy @c := (\'foo\', \'foo\');\nsay @c := (\'not-foo\', \'not-foo\');\nmy @d is List = (\'foo\', \'foo\');\nsay @d := (\'not-foo\', \'not-foo\');\nmy %e := (:foo<foo>);\nsay %e := (:not-foo<not-foo>);\n
Run Code Online (Sandbox Code Playgroud)\n

最后,问题中显示的一些示例涉及修改(伪)包的内容。这允许重新绑定,否则上述规则将禁止重新绑定:

\n
my \\foo = \'foo\';\nsay MY::<foo> := \'not-foo\';\nsub foo-fn { \'foo\' }\nMY::<&foo-fn> := { \'not-foo\' }\nsay foo-fn;\n\nmy $absolutely-foo = \'foo\';\nsub fn6 { CALLER::<$absolutely-foo> := \'not-foo\';}\nfn6;\nsay $absolutely-foo;\n
Run Code Online (Sandbox Code Playgroud)\n

然而,就像使用元对象协议访问私有方法/属性一样,使用伪包来破坏 Raku 的正常规则应该是极端的最后手段,并且不享有与 Raku 其他方面相同的稳定性保证。

\n