Я могу вызвать любой метод на ноль, и это чувствует себя неправильно - PullRequest
14 голосов
/ 10 февраля 2020

В последнее время я потратил много времени на отладку скрипта, и когда я, наконец, обнаружил проблему, это было из-за кода, который был похож на это:

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

Оказалось, что проблема была с этим $!.bar, который должен был быть либо $!bar, либо $.bar. Я получаю это.

Но , почему это не d ie?

Если взглянуть на это более подробно, похоже, проблема в том, что я ' я пытаюсь вызвать (несуществующий) метод bar на $!, который на данный момент равен Nil, потому что не было никаких ошибок.

И это Похоже, я действительно могу вызвать любой метод, который я хочу на Nil, и все они молча возвращают Nil, включая такие вещи, как Nil.this-is-a-fake-method и Nil.reverse-entropy(123).

Это функция? Если да, то в чем смысл?

Ответы [ 2 ]

13 голосов
/ 10 февраля 2020

Это задумано и задокументировано, да. Заголовок для Nil - «Отсутствие значения или доброкачественная ошибка», а в документации класса упоминается

Любой вызов метода на Nil метода, который выполняет не существует, и, следовательно, любая операция подписки будет выполнена успешно и вернет Nil.

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

Сводка 2 состояния "Любой неопределенный вызов метода для Nil возвращает Nil, так что Nil распространяется вниз по цепочкам вызовов методов. Аналогично, любая операция подписки на Nil возвращает Nil ", поэтому намерение, по-видимому, разрешает выражения типа $foo.Bar()[0].Baz(), не требуя проверки на Nil на каждом шаге или специальные вызовы метода «Nil-safe» и операторы подписки.

5 голосов
/ 22 февраля 2020

Этот вопрос (и ответ Хоббса) также заставил меня чувствовать себя ... неловко: я в конечном итоге нашел https://docs.raku.org/language/traps: это объясняет, что присвоение Nil дает другое значение, обычно Any. Следующее базовое c 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))

... поэтому общая идея заключается в том, что «отсутствующее значение или доброкачественный сбой» гораздо менее распространен в обычном коде, чем я (и, возможно, и вы?) Внезапно опасался: однако это происходит, когда вы собираетесь работать с регулярными выражениями напрямую и в вашей конкретной случайной ситуации, связанной с прямым вызовом методов для $!.

. Это позволило мне лучше понять разницу между Nil и Any и предоставленное обоснование имело для меня больше смысла.

...