Я можу викликати будь-який метод на Nil, і це відчуває себе неправильно


14

Нещодавно я витратив чималий час налагодження сценарію, і коли нарешті знайшов проблему, це було через код, який виглядав приблизно так:

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

Виявилося, проблема була в тому $!.bar, що мало бути $!barабо $.bar. Я це розумію.

Але чому це не вмирає ?

Дивлячись на це більш докладно, схоже , питання тут в тому , що я намагаюся викликати (неіснуючий) метод barна $!, який в даний момент є , Nilтому що не було ніяких помилок.

І схоже, я можу насправді викликати будь-який метод, який я хочу, Nilі всі вони мовчки повертаються Nil, включаючи такі речі, як Nil.this-is-a-fake-methodі Nil.reverse-entropy(123).

Це особливість? Якщо так, то яке обгрунтування?

Відповіді:


13

Це задумано і задокументовано, так. Заголовок для 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 "оператори виклику методу та підписки.


4
Справді. І вже досить давно: github.com/rakudo/rakudo/commit/174727377f (грудень 2013 р.) Дивіться також супутні спекуляції: design.raku.org/S02.html#Nil
Елізабет Маттійсен

1
@ElizabethMattijsen ах, я думаю, що у S02 є відповідь. "Будь-який невизначений метод викликає Nilповернення Nil, так що Nilпоширює ланцюги викликів методу вниз." Тому призначено, що ви можете обійтися $foo.Bar().Baz().Blah()без необхідності тестування нуля на кожному кроці або спеціального ?.оператора (доки ви правильно обробляєте нуль в кінці). Я відредагую це, дякую.
варення

1
NilЦе не помилка , а просто відкидає більш Nilотримує досить широке застосування в Obj-C і NS рамкові , де вона використовується таким же чином - дозволяє зчеплених викликів , які продовжують проходити по Нілу. Я не знаю точних штрафних покарань винятків та їх вилучення, але я гадаю, що Nilланцюжок може бути ефективнішим, якщо менш гнучким.
користувач0721090601

1
(але це абсолютно неінформована здогадка, тому я радий за lizmat або jnthn, щоб сказати мені, що я помиляюся, і що мені потрібно заткнутись :-))
user0721090601

2
NilКлас має FALLBACK docs.raku.org/language/typesystem#index-entry-FALLBACK_(method) метод, який повертає Nil. По суті, перед викидом винятку, оскільки методу не вдалося знайти, робиться перевірка на наявність FALLBACKі викликається, якщо вона є.
Елізабет Маттійсен

5

Це питання (і відповідь Хоббса) також змусило мене почувати себе непросто: я врешті-решт знайшов 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 ))

... тож загальна думка полягає в тому, що "відсутнє значення або доброякісний збій" є набагато менш поширеним у регулярному коді, ніж я (а можливо, і ви?) раптом побоювалися: це все ж виникає, коли ви збираєтесь працювати з регулярним виразом відповідає безпосередньо та у вашій конкретній випадковій ситуації, пов’язаній із методами прямого виклику $!.

Це зробило мене більш обізнаним про різницю між Nilта Any, і надане обґрунтування мало більше сенсу для мене.


2
Nilвстановлює контейнер у стан за замовчуванням. Ви можете змінити значення за замовчуванням. my $foo is default(42) = 5; $foo = Nil; say $foo; # 42
Бред Гілберт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.