我可以在 Nil 上调用任何方法,这感觉不对

I can call any method on Nil and this feels wrong

我最近花了很多时间调试脚本,当我终于找到问题时,是因为代码如下所示:

class Foo {
    has $.bar;
    method () {
        # do stuff
        $!.bar;
    }
}

原来问题出在 $!.bar 上,它应该是 $!bar$.bar。我明白了。

但是为什么这个不死

更详细地看一下,这里的问题似乎是我试图在 $! 上调用一个(不存在的)方法 bar,此时是Nil 因为没有任何错误。

看起来我实际上可以在 Nil 上调用我想要的任何方法,它们都默默地 return Nil,包括 Nil.this-is-a-fake-method 和 [=20] =].

这是一个功能吗?如果是这样,理由是什么?

它是有意并记录在案的,是的。 Nil 的标题是 "Absence of a value or a benign failure",class documentation 提及

Any method call on Nil of a method that does not exist, and consequently, any subscripting operation, will succeed and return Nil.

say Nil.ITotallyJustMadeThisUp;  # OUTPUT: «Nil␤» 
say (Nil)[100];                  # OUTPUT: «Nil␤» 
say (Nil){100};                  # OUTPUT: «Nil␤»

Synopsis 2 声明 "Any undefined method call on Nil returns Nil, so that Nil propagates down method call chains. Likewise any subscripting operation on Nil returns Nil",因此其意图似乎是允许像 $foo.Bar()[0].Baz() 这样的表达式,而不需要在每一步检查 Nil 或特殊的 "Nil-safe" 方法调用和下标运算符。

这个问题(和霍布斯的回答)也让我感到...不安:我最终发现https://docs.raku.org/language/traps:它解释了分配Nil会产生不同的值,通常Any.以下基本 REPL 交互也证明了这一点:

> my $foo = Nil
(Any)

> $foo.bar
No such method 'bar' for invocant of type 'Any'
  in block <unit> at <unknown file> line 1

> my $bar := Nil
Nil

> $bar.baz
Nil

(( =:= 的区别在这里:https://docs.raku.org/language/containers#Binding ))

...所以一般的想法是 'absent value or benign failure' 在常规代码中的普及程度远不如我(也许你也是?)突然担心:它确实发生了,但是,当你要使用正则表达式匹配 直接 并且在您特定的意外情况下直接调用 $!.

上的方法

这让我更加了解 NilAny 之间的区别,并且提供的基本原理对我来说更有意义。