2009-03-28 31 views
12

Tôi đang thiết kế một ngôn ngữ và tôi tự hỏi liệu có hợp lý để tạo các kiểu tham chiếu không nullable theo mặc định hay không và sử dụng "?" cho giá trị nullable và các kiểu tham chiếu. Có vấn đề gì với điều này không? Bạn sẽ làm gì về điều này:Các loại tham chiếu không thể null

class Foo { 
    Bar? b; 
    Bar b2; 
    Foo() { 
     b.DoSomething(); //valid, but will cause exception 
     b2.DoSomething(); //? 
    } 
} 
+0

có thể trùng lặp [Giải thích tốt nhất cho các ngôn ngữ không có giá trị rỗng] (http://stackoverflow.com/questions/3989264/best-explanation-for-languages-without-null) – nawfal

Trả lời

16

Triết lý thiết kế ngôn ngữ hiện tại của tôi là khả năng vô hiệu hóa phải là thứ mà một lập trình viên buộc phải yêu cầu, không được đưa ra mặc định trên các loại tham chiếu (trong trường hợp này, tôi đồng ý với Tony Hoare - Google cho bài nói chuyện QCon gần đây của mình). Trong ví dụ cụ thể này, với b2 không cần thiết, nó thậm chí sẽ không vượt qua kiểm tra tĩnh: Phân tích thận trọng không thể đảm bảo rằng b2 không phải là NULL, do đó chương trình không có ý nghĩa về mặt ngữ nghĩa.

Đặc tính của tôi đủ đơn giản. Tài liệu tham khảo là một xử lý gián tiếp đối với một số tài nguyên, mà chúng ta có thể duyệt để có được quyền truy cập vào tài nguyên đó. Tài liệu tham khảo dễ vỡ là hoặc một điều khiển vô hướng đối với tài nguyên, hoặc thông báo rằng tài nguyên không có sẵn và không bao giờ chắc chắn sẽ sử dụng ngữ nghĩa trước. Điều này cho phép hoặc vô số kiểm tra lên phía trước (Có phải là null? Không? Yay!), Hoặc NPE không thể tránh khỏi (hoặc tương đương). Hầu hết các tài nguyên lập trình là, những ngày này, không phải là nguồn lực bị hạn chế hoặc bị ràng buộc với một số mô hình cơ bản hữu hạn - tham chiếu null là, đơn giản, một trong số ...

  • Laziness: "Tôi sẽ bung một null ở đây" . Nói thẳng ra, tôi không có quá nhiều thông cảm với
  • Lẫn lộn: "Tôi không biết phải đặt gì ở đây". Thông thường cũng là một di sản của các ngôn ngữ cũ, nơi bạn phải khai báo tên tài nguyên trước khi bạn biết tài nguyên của mình là gì.
  • Lỗi: "Đã xảy ra lỗi, đây là NULL". Do đó, cơ chế báo cáo lỗi tốt hơn là cần thiết trong một ngôn ngữ
  • Một lỗ: "Tôi biết tôi sẽ sớm có thứ gì đó, hãy cho tôi một trình giữ chỗ". Điều này có nhiều công đức hơn, và chúng ta có thể nghĩ ra cách để chống lại điều này.

Tất nhiên, giải quyết từng trường hợp mà NULL hiện đang phục vụ với một lựa chọn ngôn ngữ tốt hơn là không có kỳ tích nhỏ và có thể thêm nhiều sự nhầm lẫn mà nó giúp. Chúng ta luôn có thể đi đến các tài nguyên không thay đổi được, do đó, NULL ở trạng thái hữu ích duy nhất của nó (lỗi và lỗ hổng) không được sử dụng nhiều. Kỹ thuật bắt buộc là ở đây để ở lại mặc dù, và tôi thẳng thắn vui mừng - điều này làm cho việc tìm kiếm các giải pháp tốt hơn trong không gian này đáng giá.

3

Một vài ví dụ về các tính năng tương tự trong các ngôn ngữ khác:

Ngoài ra còn có Nullable<T> (từ C#) nhưng đó không phải là một ví dụ tốt vì điều trị khác nhau của các loại tham chiếu và giá trị.

Trong ví dụ của bạn, bạn có thể thêm toán tử gửi tin nhắn có điều kiện, ví dụ:

b?->DoSomething(); 

Chỉ gửi thư đến b nếu thư không rỗng.

4

Hãy xem đề xuất Elvis operator dành cho Java 7.Điều này làm một cái gì đó tương tự, trong đó nó đóng gói một kiểm tra null và phương thức công văn trong một nhà điều hành, với một giá trị trả về xác định nếu đối tượng là null. Do đó:

String s = mayBeNull?.toString() ?: "null"; 

kiểm tra xem chuỗi có rỗng hay không và trả về chuỗi "null" nếu có và giá trị của chuỗi nếu không. Thực phẩm cho ý nghĩ, có lẽ.

+3

Tại sao điều này được gọi là toán tử Elvis? – Zifre

+0

Câu hỏi hay và tôi không biết câu trả lời. Tuy nhiên, hãy xem http://www.infoq.com/articles/groovy-1.5-new re. toán tử?:, có liên quan. Tuy nhiên, một chút ít có liên quan ... –

+0

Tôi chỉ có thể giả định rằng đó là một số trò đùa về việc phải làm gì nếu đối tượng "rời khỏi tòa nhà"? –

11

Mặc dù loại tham chiếu không thể vô hiệu hóa là lựa chọn hợp lý duy nhất. Chúng tôi bị cản trở bởi ngôn ngữ và thời gian chạy đã làm hỏng điều này; bạn nên làm điều đúng.

+0

Hãy xem xét giải thích vị trí giáo điều của bạn. – Kromster

-3

Tôi nghĩ giá trị null là tốt: Chúng là dấu hiệu rõ ràng rằng bạn đã làm điều gì đó sai. Nếu bạn không khởi tạo tham chiếu ở đâu đó, bạn sẽ nhận được thông báo ngay lập tức.

Thay thế sẽ là giá trị đôi khi được khởi tạo thành giá trị mặc định. Các lỗi logic sau đó sẽ khó phát hiện hơn nhiều, trừ khi bạn đặt logic phát hiện trong các giá trị mặc định đó. Điều này sẽ giống như chỉ nhận được một ngoại lệ con trỏ null.

+0

Đôi khi cần thiết để khởi tạo một cái gì đó mà không biết giá trị cuối cùng sẽ mất. Điều này là khá hiếm, mặc dù. Thông thường, việc khởi tạo diễn ra trên cùng một dòng với khai báo. Ngoài ra, đề xuất không loại bỏ các giá trị null, chỉ làm cho chúng không rỗng theo mặc định. – kvb

+2

Ngoài ra, không đúng là bạn sẽ nhận được thông báo ngay lập tức. Bạn sẽ nhận được một ngoại lệ ngay sau khi bạn cố gắng dereference giá trị null, nhưng ngoại lệ đó có thể bị bắt, và bạn sẽ chỉ tìm ra trong thời gian chạy, không biên dịch thời gian. – kvb

+1

Vấn đề là, bạn không thể buộc các lập trình viên khởi tạo một biến đúng: Đã bao nhiêu lần bạn nhìn thấy: Số liệu ds = new DataSet(); ... ds = ReadDataSet (...); trong mã? Nếu ds là không nullable, không có lỗi sẽ được phát hiện nếu các cuộc gọi đến ReadDataSet() đã bị lãng quên. – Lennaert

9

Tính năng này ở số Spec#. Chúng được mặc định là tham chiếu nullable và được sử dụng! để chỉ ra các giá trị không null. Điều này là bởi vì họ muốn tương thích ngược.

Trong ngôn ngữ mơ ước của tôi (trong đó tôi có thể là người dùng duy nhất!) Tôi sẽ đưa ra lựa chọn tương tự như bạn, không thể vô hiệu theo mặc định.

Tôi cũng sẽ làm cho việc sử dụng. nhà điều hành trên một tham chiếu nullable (hoặc bất cứ điều gì khác mà sẽ dereference nó). Bạn sẽ sử dụng chúng như thế nào? Bạn sẽ phải chuyển đổi chúng thành không phải nullables trước. Bạn sẽ làm điều này như thế nào? Bằng cách kiểm tra chúng cho null.

Trong Java và C#, câu lệnh if chỉ có thể chấp nhận biểu thức kiểm tra bool. Tôi muốn mở rộng nó để chấp nhận tên của biến tham chiếu có thể vô hiệu hóa:

if (myObj) 
{ 
    // in this scope, myObj is non-nullable, so can be used 
} 

Cú pháp đặc biệt này sẽ không gây ngạc nhiên cho người lập trình C/C++. Tôi thích một cú pháp đặc biệt như thế này để làm cho nó rõ ràng rằng chúng tôi đang làm một kiểm tra mà sửa đổi các loại tên myObj trong sự thật-chi nhánh.

Tôi muốn thêm một chút nữa đường:

if (SomeMethodReturningANullable() into anotherObj) 
{ 
    // anotherObj is non-nullable, so can be used 
} 

này chỉ cung cấp cho các tên anotherObj đến kết quả của biểu thức ở bên trái của into, vì vậy nó có thể được sử dụng trong phạm vi nơi nó hợp lệ.

Tôi sẽ làm điều tương tự cho toán tử ?:.

string message = GetMessage() into m ? m : "No message available"; 

Lưu ý rằng string message là không nullable, nhưng như vậy là hai kết quả có thể có của các bài kiểm tra trên, vì vậy việc chuyển nhượng là giá trị.

Và sau đó có thể là một chút đường đối với trường hợp có lẽ phổ biến thay thế một giá trị cho null:

string message = GetMessage() or "No message available"; 

Rõ ràng or sẽ chỉ được hợp lệ áp dụng cho một loại nullable ở phía bên trái, và một phi nullable ở phía bên phải.

(Tôi cũng muốn có một built-in khái niệm về quyền sở hữu cho instance fields;. Trình biên dịch sẽ tạo ra các phương pháp IDisposable.Dispose tự động, và cú pháp ~Destructor sẽ được sử dụng để tăng thêm Dispose, chính xác như trong C++/CLI)

SpeC# đã có một phần mở rộng cú pháp liên quan đến phi nullables, do các vấn đề về đảm bảo rằng không nullables đã được khởi tạo một cách chính xác trong quá trình thi:

class SpecSharpExampleClass 
{ 
    private string! _nonNullableExampleField; 

    public SpecSharpExampleClass(string s) 
     : _nonNullableExampleField(s) 
    { 

    } 
} 

Nói cách khác, bạn phải khởi tạo các trường trong giống như cách bạn gọi với các nhà thầu khác base hoặc this - trừ khi tất nhiên bạn khởi tạo chúng trực tiếp bên cạnh khai báo trường.

+0

trong câu đầu tiên của bạn, bạn nói "họ mặc định để tham chiếu nullable", bạn có nghĩa là không nullable? –

+1

@Janan Venge - Không. Trong cùng một câu, tôi giải thích lý do: SpeC# đã cố gắng biên dịch mã C# hiện tại một cách chính xác, vì vậy tham chiếu phải được giả định là không thể trừ khi mã chỉ ra khác. –

+1

Cảm ơn Daniel. Tôi nghĩ SpeC# đã được mặc định nếu không, vì họ nghĩ rằng nó là tốt hơn, nhưng tôi hiểu những gì bạn có ý nghĩa bây giờ. –

-1

Có tính khả dụng là cài đặt cấu hình, có thể thực thi trong mã nguồn của tác giả. Bằng cách đó, bạn sẽ cho phép những người thích các đối tượng nullable theo mặc định tận hưởng chúng trong mã nguồn của họ, trong khi cho phép những người muốn tất cả các đối tượng của họ không có giá trị mặc định có chính xác điều đó. Ngoài ra, hãy cung cấp từ khóa hoặc cơ sở khác để đánh dấu rõ ràng các khai báo đối tượng và kiểu của bạn có thể rỗng và không thể, với một số thứ như nullablenot-nullable, để ghi đè các giá trị mặc định chung.

Ví dụ

/// "translation unit 1" 

#set nullable 
{ /// Scope of default override, making all declarations within the scope nullable implicitly 
    Bar bar; /// Can be null 
    non-null Foo foo; /// Overriden, cannot be null 
    nullable FooBar foobar; /// Overriden, can be null, even without the scope definition above 
} 

/// Same style for opposite 

/// ... 

/// Top-bottom, until reset by scoped-setting or simply reset to another value 
#set nullable; 

/// Nullable types implicitly 

#clear nullable; 

/// Can also use '#set nullable = false' or '#set not-nullable = true'. Ugly, but human mind is a very original, mhm, thing. 

Nhiều người cho rằng cho tất cả mọi người những gì họ muốn là không thể, nhưng nếu bạn đang thiết kế một ngôn ngữ mới, hãy thử những điều mới mẻ. Tony Hoare giới thiệu khái niệm null vào năm 1965 bởi vì anh ta không thể cưỡng lại (lời nói của chính mình), và chúng tôi đang trả tiền cho nó kể từ đó (cũng vậy, lời của anh ta, người đàn ông rất hối hận về nó). Điểm là, thông minh, những người có kinh nghiệm làm cho những sai lầm mà chi phí phần còn lại của chúng tôi, không có lời khuyên anyones trên trang này như thể nó là sự thật duy nhất, bao gồm cả tôi. Đánh giá và suy nghĩ về nó.

Tôi đã đọc rất nhiều bài viết về cách chúng tôi nghèo lập trình viên thiếu kinh nghiệm, những người thực sự không hiểu nơi để thực sự sử dụng null và nơi không, cho chúng ta thấy các mẫu và antipatterns có nghĩa là để ngăn chặn chụp mình trong bàn chân. Trong khi đó, hàng triệu lập trình viên thiếu kinh nghiệm vẫn tạo ra nhiều mã hơn bằng các ngôn ngữ cho phép null. Tôi có thể là thiếu kinh nghiệm, nhưng tôi biết đối tượng nào của tôi không được hưởng lợi từ việc không có giá trị.

+0

Tại sao lại là downvote? Bạn đã từng thấy những chương trình lớn trông như thế nào với gần như mọi tham chiếu đơn lẻ đều có tiền tố giống như '@ NonNull'? Đôi khi tôi bị sốc bởi tình trạng khoa học máy tính, nhưng sau đó những gì khác nó mới. Chúng tôi xứng đáng với các chương trình chúng tôi có :-) – amn

Các vấn đề liên quan