Tôi có thể gọi bất kỳ phương thức nào trên Nil và điều này cảm thấy sai


14

Tôi đã dành thời gian đáng kể để gỡ lỗi một tập lệnh gần đây và cuối cùng khi tôi tìm thấy vấn đề là do mã trông như thế này:

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

Hóa ra vấn đề là với điều đó $!.bar, mà cần phải có được một trong hai $!barhoặc $.bar. Tôi nhận được điều này.

Nhưng tại sao điều này không chết ?

Nhìn vào này chi tiết hơn, có vẻ như vấn đề ở đây là tôi đang cố gắng để gọi một phương thức (không tồn tại) bartrên $!, mà vào thời điểm này là Nilbởi vì có chưa được bất kỳ lỗi nào.

Và có vẻ như tôi thực sự có thể gọi bất kỳ phương thức nào tôi muốn Nilvà tất cả đều âm thầm trở lại Nil, bao gồm cả những thứ như Nil.this-is-a-fake-methodNil.reverse-entropy(123).

Đây có phải là một tính năng? Nếu vậy, lý do là gì?

Câu trả lời:


13

Đó là dự định và tài liệu, có. Tiêu đề cho Nillà "Sự vắng mặt của một giá trị hoặc một sự thất bại lành tính" và tài liệu lớp đề cập đến

Bất kỳ phương thức nào gọi Nilmột phương thức không tồn tại, và do đó, bất kỳ hoạt động đăng ký nào, sẽ thành công và trả về Nil.

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

Tóm tắt 2 tuyên bố "Bất kỳ phương thức nào không xác định đều gọi Niltrả về Nil, để Niltruyền xuống chuỗi cuộc gọi phương thức. Tương tự như vậy, bất kỳ thao tác đăng ký nào trên Niltrả về Nil", do đó, ý định dường như cho phép các biểu thức như $foo.Bar()[0].Baz()không yêu cầu kiểm tra Nilở mọi bước hoặc đặc biệt "Không an toàn "Phương thức gọi và toán tử đăng ký.


4
Thật. Và cũng khá lâu rồi: github.com/rakudo/rakudo/commit/174727377f (tháng 12 năm 2013) Xem thêm suy đoán liên quan: design.raku.org/S02.html#Nil
Elizabeth Mattijsen

1
@ElizabethMattijsen ah, tôi nghĩ S02 có câu trả lời. "Bất kỳ phương thức không xác định nào gọi về Niltrả về Nil, để Niltruyền xuống chuỗi cuộc gọi phương thức." Vì vậy, dự định là bạn có thể làm $foo.Bar().Baz().Blah()mà không cần các thử nghiệm không ở mọi bước hoặc một ?.loại toán tử đặc biệt (miễn là bạn xử lý chính xác con số không ở cuối). Tôi sẽ chỉnh sửa nó trong, cảm ơn bạn.
hobbs

1
Một Nillỗi không xảy ra và chỉ ném lại Nilđược sử dụng khá rộng rãi trong Obj-C và NS Framework trong đó nó được sử dụng theo cách tương tự - cho phép các cuộc gọi bị xiềng xích tiếp tục truyền đến Nil. Tôi không biết các hình phạt hiệu suất chính xác của các trường hợp ngoại lệ và bắt chúng, nhưng tôi đoán là việc Nilxâu chuỗi có thể hiệu quả hơn, nếu kém linh hoạt.
user0721090601

1
(nhưng đó là một phỏng đoán hoàn toàn không có thông tin, vì vậy tôi rất vui khi lizmat hoặc jnthn nói với tôi rằng tôi sai và tôi cần phải im lặng :-))
user0721090601

2
Các Nillớp học có một FALLBACK docs.raku.org/language/typesystem#index-entry-FALLBACK_(method) phương pháp, trong đó lợi nhuận Nil. Về cơ bản, ngay trước khi ném ngoại lệ vì không thể tìm thấy phương thức, kiểm tra FALLBACKđược thực hiện và được gọi nếu có sẵn.
Elizabeth Mattijsen

5

Câu hỏi này (và câu trả lời của hobbs) cũng khiến tôi cảm thấy ... khó chịu: Cuối cùng tôi đã tìm thấy https://docs.raku.org/lingu/traps : nó giải thích rằng việc gán thường Niltạo ra một giá trị khác Any. Tương tác REPL cơ bản sau đây cũng thể hiện điều này:

> 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

((sự khác biệt giữa =:=được đề cập ở đây: https://docs.raku.org/lingu/containers#Binding ))

... Vì vậy, ý tưởng chung là 'giá trị vắng mặt hoặc thất bại lành tính' ít phổ biến hơn trong mã thông thường so với tôi (và có lẽ bạn cũng vậy?) đột nhiên lo sợ: tuy nhiên, điều đó xảy ra khi bạn sẽ làm việc với regex khớp trực tiếp và trong tình huống ngẫu nhiên cụ thể của bạn liên quan đến các phương thức gọi trực tiếp trên $!.

Điều này làm cho tôi nhận thức rõ hơn về sự khác biệt giữa NilAny, và lý do được cung cấp có ý nghĩa hơn đối với tôi.


2
Nilđặt một thùng chứa về trạng thái mặc định của nó. Bạn có thể thay đổi giá trị mặc định. my $foo is default(42) = 5; $foo = Nil; say $foo; # 42
Brad Gilbert
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.