Tại sao hầu hết các ngôn ngữ bắt buộc / OO nổi tiếng của người Viking cho phép truy cập không được kiểm tra vào các loại có thể đại diện cho giá trị 'không có gì'?


29

Tôi đã đọc về sự tiện lợi (un) của việc có nullthay vì (ví dụ) Maybe. Sau khi đọc bài viết này , tôi tin rằng sẽ tốt hơn nếu sử dụngMaybe (hoặc một cái gì đó tương tự). Tuy nhiên, tôi ngạc nhiên khi thấy rằng tất cả các ngôn ngữ lập trình bắt buộc hoặc hướng đối tượng "nổi tiếng" vẫn sử dụng null(cho phép truy cập không được kiểm soát vào các loại có thể biểu thị giá trị 'không có gì') và Maybechủ yếu được sử dụng trong các ngôn ngữ lập trình chức năng.

Ví dụ, xem mã C # sau:

void doSomething(string username)
{
    // Check that username is not null
    // Do something
}

Một cái gì đó có mùi ở đây ... Tại sao chúng ta nên kiểm tra nếu đối số là null? Chúng ta không nên cho rằng mỗi biến chứa tham chiếu đến một đối tượng? Như bạn có thể thấy, vấn đề là theo định nghĩa, hầu hết các biến đều có thể chứa tham chiếu null. Điều gì xảy ra nếu chúng ta có thể quyết định biến nào là "nullable" và biến nào không? Điều đó sẽ giúp chúng tôi tiết kiệm rất nhiều nỗ lực trong khi gỡ lỗi và tìm kiếm "NullReferenceException". Hãy tưởng tượng rằng, theo mặc định, không có loại nào có thể chứa tham chiếu null . Thay vào đó, bạn sẽ tuyên bố rõ ràng rằng một biến có thể chứa tham chiếu null , chỉ khi bạn thực sự cần nó. Đó là ý tưởng đằng sau Có lẽ. Nếu bạn có một hàm mà trong một số trường hợp không thành công (ví dụ: chia cho 0), bạn có thể trả vềMaybe<int>, nói rõ rằng kết quả có thể là một int, nhưng cũng không có gì! Đây là một lý do để thích Có thể thay vì null. Nếu bạn quan tâm đến nhiều ví dụ hơn, thì tôi khuyên bạn nên đọc bài viết này .

Sự thật là, mặc dù những nhược điểm của việc biến hầu hết các loại thành không thể mặc định, hầu hết các ngôn ngữ lập trình OO thực sự làm điều đó. Đó là lý do tại sao tôi tự hỏi về:

  • Những loại đối số nào bạn sẽ phải thực hiện nulltrong ngôn ngữ lập trình của bạn thay vì Maybe? Có lý do nào không hay đó chỉ là "hành lý lịch sử"?

Vui lòng đảm bảo bạn hiểu sự khác biệt giữa null và Có thể trước khi trả lời câu hỏi này.


3
Tôi đề nghị đọc lên về Tony Hoare , đặc biệt là sai lầm tỷ đô của anh ấy.
Oded 15/12/13

2
Vâng, đó là ông có lý do. Và kết quả không may là đó là một lỗi được sao chép sang hầu hết các ngôn ngữ tiếp theo, cho đến ngày hôm nay. Có những ngôn ngữ mà nullkhái niệm của nó không tồn tại (IIRC Haskell là một ví dụ như vậy).
Oded

9
Hành lý lịch sử không phải là một cái gì đó để đánh giá thấp. Và hãy nhớ rằng các hệ điều hành được xây dựng trên được viết bằng các ngôn ngữ đã có nulltrong chúng trong một thời gian dài. Không dễ để bỏ nó.
Oded 15/12/13

3
Tôi nghĩ bạn nên làm sáng tỏ khái niệm Có thể thay vì đăng một liên kết.
JeffO

1
@ GlenH7 Chuỗi trong C # là giá trị tham chiếu (chúng có thể là null). Tôi biết rằng int là một giá trị nguyên thủy, nhưng nó hữu ích để hiển thị việc sử dụng có thể.
aochagavia

Câu trả lời:


15

Tôi tin rằng nó chủ yếu là hành lý lịch sử.

Ngôn ngữ nổi bật nhất và lâu đời nhất nulllà C và C ++. Nhưng ở đây, nullcó ý nghĩa. Con trỏ vẫn là khái niệm khá số và cấp thấp. Và người khác đã nói như thế nào, trong suy nghĩ của các lập trình viên C và C ++, việc phải nói rõ ràng rằng con trỏ có thể nullkhông có ý nghĩa gì.

Dòng thứ hai đến Java. Xem xét các nhà phát triển Java đã cố gắng tiếp cận gần nhất với C ++, vì vậy họ có thể thực hiện quá trình chuyển đổi từ C ++ sang Java đơn giản hơn, có lẽ họ không muốn gây rối với khái niệm cốt lõi của ngôn ngữ này. Ngoài ra, việc triển khai rõ ràng nullsẽ đòi hỏi nhiều nỗ lực hơn, bởi vì bạn phải kiểm tra xem tham chiếu không null có thực sự được đặt đúng sau khi khởi tạo hay không.

Tất cả các ngôn ngữ khác đều giống như Java. Họ thường sao chép cách C ++ hoặc Java thực hiện và xem xét khái niệm cốt lõi của việc ẩn nullcác loại tham chiếu là gì, thật khó để thiết kế một ngôn ngữ đang sử dụng rõ ràng null.


Họ nghĩ có lẽ họ không muốn gây rối với khái niệm cốt lõi như vậy về ngôn ngữ. Họ đã loại bỏ hoàn toàn các con trỏ, và việc loại bỏ nullsẽ không phải là một thay đổi lớn, tôi nghĩ vậy.
Svick

2
@svick Đối với Java, các tham chiếu là sự thay thế cho các con trỏ. Và trong nhiều trường hợp, các con trỏ trong C ++ đã được sử dụng theo cách tương tự như những gì các tài liệu tham khảo Java làm. Một số người thậm chí còn cho rằng Java không có con trỏ ( lập trình
viên.stackexchange.com/questions/207196/ mẹo

Tôi đã đánh dấu đây là câu trả lời đúng. Tôi muốn nâng cao nó nhưng tôi không đủ danh tiếng.
aochagavia

1
Đồng ý. Lưu ý rằng trong C ++ (không giống như Java và C), không có khả năng là ngoại lệ. std::stringkhông thể null. int&không thể null. Một int*can và C ++ cho phép không kiểm tra quyền truy cập vào nó vì hai lý do: 1. vì C đã làm và 2. vì bạn phải hiểu những gì bạn đang làm khi sử dụng con trỏ thô trong C ++.
MSalters 16/12/13

@MSalters: Nếu một loại không có giá trị mặc định có thể sao chép bit, thì việc tạo một mảng của loại đó sẽ yêu cầu gọi một hàm tạo cho mọi phần tử của nó trước khi cho phép truy cập vào chính mảng đó. Điều này có thể yêu cầu công việc vô ích (nếu một số hoặc tất cả các yếu tố sẽ bị ghi đè trước khi chúng được đọc), có thể gây ra các biến chứng nếu hàm tạo cho phần tử sau bị lỗi sau khi phần tử trước đó được tạo và cuối cùng có thể không thực sự hoàn thành nhiều ( một giá trị thích hợp cho một số phần tử mảng không thể được xác định mà không đọc các phần tử khác).
supercat

15

Trên thực tế, nulllà một ý tưởng tuyệt vời. Đưa ra một con trỏ, chúng tôi muốn chỉ định rằng con trỏ này không tham chiếu giá trị hợp lệ. Vì vậy, chúng tôi lấy một vị trí bộ nhớ, tuyên bố nó không hợp lệ và tuân theo quy ước đó (một quy ước đôi khi được thi hành với segfaults). Bây giờ bất cứ khi nào tôi có một con trỏ, tôi có thể kiểm tra xem nó có chứa Nothing( ptr == null) hoặc Some(value)( ptr != null, value = *ptr) không. Tôi muốn bạn hiểu rằng điều này tương đương với một Maybeloại.

Các vấn đề với điều này là:

  1. Trong nhiều ngôn ngữ, hệ thống loại không hỗ trợ ở đây để đảm bảo tham chiếu không null.

    Đây là hành lý lịch sử, vì nhiều ngôn ngữ bắt buộc hoặc OOP chính thống chỉ có những tiến bộ gia tăng trong hệ thống loại của họ khi so sánh với các ngôn ngữ tiền nhiệm. Những thay đổi nhỏ có lợi thế là ngôn ngữ mới dễ học hơn. C # là một ngôn ngữ chính đã giới thiệu các công cụ cấp ngôn ngữ để xử lý null tốt hơn.

  2. Các nhà thiết kế API có thể trở lại nullthất bại, nhưng không phải là một tham chiếu đến thực tế thành công. Thông thường, điều (không có tài liệu tham khảo) được trả lại trực tiếp. Việc làm phẳng một cấp con trỏ này khiến cho không thể sử dụng nulllàm giá trị.

    Đây chỉ là sự lười biếng về phía người thiết kế và không thể được giúp đỡ mà không thực thi việc lồng đúng cách với một hệ thống loại thích hợp. Một số người cũng có thể cố gắng chứng minh điều này bằng các cân nhắc về hiệu suất hoặc với sự tồn tại của các kiểm tra tùy chọn (một bộ sưu tập có thể trả về nullhoặc chính mặt hàng đó, nhưng cũng cung cấp một containsphương thức).

  3. Trong Haskell có một cái nhìn gọn gàng về Maybeloại như một đơn nguyên. Điều này làm cho việc soạn thảo các phép biến đổi trên giá trị được chứa dễ dàng hơn.

    Mặt khác, các ngôn ngữ cấp thấp như C hầu như không coi các mảng là một loại riêng biệt, vì vậy tôi không chắc chúng ta đang mong đợi điều gì. Trong các ngôn ngữ OOP có tính đa hình được tham số hóa, một Maybeloại kiểm tra thời gian chạy là khá tầm thường để thực hiện.


C C C # đang mất các bước từ tham chiếu null. Những bước đó là gì? Tôi chưa thấy bất cứ điều gì như thế trong các thay đổi về ngôn ngữ. Hay bạn có nghĩa là các thư viện phổ biến đang sử dụng nullít hơn so với trước đây?
Svick

@svick Phrasing xấu về phía tôi. “ C # là một ngôn ngữ chính thống mà đã giới thiệu công cụ ngôn ngữ cấp để xử lý tốt hơn nulls ” - tôi đang nói về Nullablecác loại và các ??nhà điều hành mặc định. Nó không giải quyết vấn đề ngay bây giờ với sự hiện diện của mã kế thừa, nhưng đó một bước tiến tới một tương lai tốt hơn.
amon

Tôi đồng ý với bạn. Tôi sẽ bỏ phiếu cho câu trả lời của bạn nhưng tôi không có tiếng tăm gì cả :( Tuy nhiên, Nullable chỉ hoạt động cho các loại nguyên thủy. Vì vậy, đây chỉ là một bước nhỏ.
aochagavia 15/12/13

1
@svick Nullable không có gì để làm với điều này. Chúng tôi đang nói về tất cả các loại tham chiếu ngầm cho phép giá trị null, thay vì có lập trình viên xác định rõ ràng. Và Nullable chỉ có thể được sử dụng trên các loại giá trị.
Euphoric

@Euphoric Tôi nghĩ rằng bình luận của bạn có ý nghĩa như một câu trả lời cho amon, tôi đã không đề cập đến Nullable.
Svick

9

Hiểu biết của tôi là đó nulllà một cấu trúc cần thiết để các ngôn ngữ lập trình trừu tượng ra khỏi lắp ráp. 1 Lập trình viên cần khả năng chỉ ra rằng một con trỏ hoặc giá trị đăng ký là not a valid valuenulltrở thành thuật ngữ chung cho ý nghĩa đó.

Củng cố điểm nullchỉ là quy ước để thể hiện một khái niệm, giá trị thực tế nullđược sử dụng để có thể / có thể thay đổi dựa trên ngôn ngữ lập trình và nền tảng.

Nếu bạn đang thiết kế một ngôn ngữ mới và muốn tránh nullnhưng sử dụng maybethay vào đó, thì tôi sẽ khuyến khích một thuật ngữ mô tả nhiều hơn như not a valid valuehoặc navvđể chỉ ý định. Nhưng tên của phi giá trị đó là một khái niệm riêng biệt với việc bạn có nên cho phép các giá trị không tồn tại thậm chí tồn tại trong ngôn ngữ của bạn hay không.

Trước khi bạn có thể quyết định một trong hai điểm đó, bạn cần xác định ý maybenghĩa của hệ thống của bạn. Bạn có thể thấy nó chỉ là một sự đổi tên của nullý nghĩa của nó not a valid valuehoặc bạn có thể thấy nó có một ngữ nghĩa khác cho ngôn ngữ của bạn.

Tương tự như vậy, quyết định về việc kiểm tra quyền truy cập đối với nullquyền truy cập hoặc tham chiếu là một quyết định thiết kế khác của ngôn ngữ của bạn.

Để cung cấp một chút lịch sử, Ccó một giả định ngầm định rằng các lập trình viên hiểu những gì họ đã cố gắng làm khi thao tác bộ nhớ. Vì nó là một sự trừu tượng hóa vượt trội để lắp ráp và các ngôn ngữ bắt buộc đi trước nó, tôi sẽ mạo hiểm rằng ý nghĩ bảo vệ an toàn cho lập trình viên khỏi một tài liệu tham khảo không chính xác đã xuất hiện trong đầu họ.

Tôi tin rằng một số trình biên dịch hoặc công cụ bổ sung của chúng có thể cung cấp một biện pháp kiểm tra đối với truy cập con trỏ không hợp lệ. Vì vậy, những người khác đã lưu ý vấn đề tiềm năng này và thực hiện các biện pháp để bảo vệ chống lại nó.

Việc bạn có nên cho phép hay không tùy thuộc vào những gì bạn muốn ngôn ngữ của mình thực hiện và mức độ trách nhiệm mà bạn muốn thúc đẩy đối với người dùng ngôn ngữ của bạn. Nó cũng phụ thuộc vào khả năng của bạn để tạo một trình biên dịch để hạn chế loại hành vi đó.

Vì vậy, để trả lời câu hỏi của bạn:

  1. "Kiểu tranh luận nào" - Chà, nó phụ thuộc vào những gì bạn muốn ngôn ngữ làm. Nếu bạn muốn mô phỏng truy cập kim loại trần thì bạn có thể muốn cho phép nó.

  2. "nó chỉ là hành lý lịch sử?" Có lẽ, có lẽ không. nullchắc chắn có / có ý nghĩa đối với một số ngôn ngữ và giúp thúc đẩy sự biểu hiện của các ngôn ngữ đó. Tiền lệ lịch sử có thể đã ảnh hưởng đến các ngôn ngữ gần đây hơn và cho phép chúng nullnhưng hơi nhiều để vẫy tay và tuyên bố khái niệm hành lý lịch sử vô dụng.


1 Xem bài viết Wikipedia này mặc dù tín dụng được trao cho Hoare cho các giá trị null và ngôn ngữ hướng đối tượng. Tôi tin rằng các ngôn ngữ bắt buộc tiến triển dọc theo một cây gia đình khác với Algol đã làm.


Vấn đề là hầu hết các biến trong, giả sử, C # hoặc Java, có thể được chỉ định một tham chiếu null. Có vẻ như sẽ tốt hơn nhiều nếu chỉ gán tham chiếu null cho các đối tượng chỉ ra rõ ràng rằng "Có thể" không có tham chiếu. Vì vậy, câu hỏi của tôi là về "khái niệm" null, và không phải từ.
aochagavia

2
Các tham chiếu con trỏ của Null có thể hiển thị dưới dạng lỗi trong quá trình biên dịch. Trình biên dịch nào có thể làm điều đó?
Svick

Để hoàn toàn công bằng, bạn không bao giờ gán tham chiếu null cho một đối tượng ... tham chiếu đến đối tượng chỉ không tồn tại (các điểm tham chiếu không là gì (0x000000000), theo định nghĩa null).
mgw854

Trích dẫn của C99 spec nói về ký tự null , không phải con trỏ null , đó là hai khái niệm rất khác nhau.
Svick

2
@ GlenH7 Nó không làm điều đó cho tôi. Mã object o = null; o.ToString();biên dịch tốt cho tôi, không có lỗi hoặc cảnh báo trong VS2012. ReSharper phàn nàn về điều đó, nhưng đó không phải là trình biên dịch.
Svick

7

Nếu bạn xem các ví dụ trong bài viết bạn đã trích dẫn, phần lớn thời gian sử dụng Maybekhông rút ngắn mã. Nó không làm giảm nhu cầu kiểm tra Nothing. Sự khác biệt duy nhất là nó nhắc nhở bạn làm như vậy thông qua hệ thống loại.

Lưu ý, tôi nói "nhắc nhở", không ép buộc. Lập trình viên lười biếng. Nếu một lập trình viên bị thuyết phục một giá trị không thể có thể Nothing, thì họ sẽ hủy đăng ký Maybemà không kiểm tra nó, giống như họ đang hủy bỏ một con trỏ rỗng bây giờ. Kết quả cuối cùng là bạn chuyển đổi một ngoại lệ con trỏ null thành một ngoại lệ "có thể bỏ trống có thể".

Nguyên tắc tương tự của bản chất con người áp dụng trong các lĩnh vực khác, nơi các ngôn ngữ lập trình cố gắng buộc các lập trình viên phải làm một cái gì đó. Ví dụ, các nhà thiết kế Java đã cố gắng buộc mọi người xử lý hầu hết các trường hợp ngoại lệ, điều này dẫn đến rất nhiều bản tóm tắt mà âm thầm bỏ qua hoặc truyền bá ngoại lệ một cách mù quáng.

Điều làm cho Maybetốt đẹp là khi rất nhiều quyết định được đưa ra thông qua khớp mẫu và đa hình thay vì kiểm tra rõ ràng. Ví dụ: bạn có thể tạo các chức năng riêng biệt processData(Some<T>)processData(Nothing<T>), bạn không thể thực hiện được null. Bạn tự động chuyển việc xử lý lỗi của mình sang một chức năng riêng biệt, điều rất mong muốn trong lập trình chức năng nơi các chức năng được truyền qua và đánh giá một cách lười biếng thay vì luôn được gọi theo cách từ trên xuống. Trong OOP, cách ưa thích để tách mã xử lý lỗi của bạn là ngoại lệ.


Bạn có nghĩ rằng nó sẽ là một tính năng mong muốn trong một ngôn ngữ OO mới không?
aochagavia

Bạn có thể tự thực hiện nếu bạn muốn có được lợi ích đa hình. Điều duy nhất bạn cần hỗ trợ ngôn ngữ là không có giá trị. Tôi rất thích xem một cách để xác định điều đó cho chính mình, tương tự const, nhưng làm cho nó tùy chọn. Một số loại mã cấp thấp hơn, chẳng hạn như danh sách được liên kết chẳng hạn, sẽ rất khó thực hiện với các đối tượng không thể rỗng.
Karl Bielefeldt

2
Bạn không cần phải kiểm tra với loại Có thể. Kiểu Có thể là một đơn nguyên, do đó, nó phải có các hàm map :: Maybe a -> (a -> b)bind :: Maybe a -> (a -> Maybe b)được định nghĩa trên nó, vì vậy bạn có thể tiếp tục và xâu chuỗi các tính toán tiếp theo cho hầu hết các phần với việc sử dụng lại câu lệnh if if. Và getValueOrDefault :: Maybe a -> (() -> a) -> acho phép bạn xử lý các trường hợp nullable. Nó thanh lịch hơn nhiều so với kết hợp mẫu trên Maybe arõ ràng.
DetriusXii

1

Maybelà một cách suy nghĩ rất chức năng của một vấn đề - có một điều, và nó có thể có hoặc không có một giá trị được xác định. Tuy nhiên, theo nghĩa hướng đối tượng, chúng tôi thay thế ý tưởng đó về một sự vật (bất kể nó có giá trị hay không) bằng một đối tượng. Rõ ràng, một đối tượng có một giá trị. Nếu không, chúng tôi nói đối tượng là null, nhưng điều chúng tôi thực sự muốn nói là không có đối tượng nào cả. Các tài liệu tham khảo chúng ta phải đối tượng chỉ ra không có gì. Chuyển Maybethành một khái niệm OO không có gì mới lạ - trên thực tế, nó chỉ làm cho mã bị lộn xộn hơn nhiều. Bạn vẫn phải có một tham chiếu null cho giá trị củaMaybe<T>. Bạn vẫn phải thực hiện kiểm tra null (trên thực tế, bạn phải thực hiện nhiều kiểm tra null hơn, làm lộn xộn mã của bạn), ngay cả khi bây giờ chúng được gọi là "có thể kiểm tra". Chắc chắn, bạn sẽ viết mã mạnh mẽ hơn như tác giả tuyên bố, nhưng tôi cho rằng đó chỉ là trường hợp vì bạn đã làm cho ngôn ngữ trở nên trừu tượng và khó hiểu hơn, đòi hỏi mức độ công việc không cần thiết trong hầu hết các trường hợp. Tôi sẵn sàng sử dụng NullReferenceException một lần trong một thời gian hơn là đối phó với mã spaghetti khi thực hiện Kiểm tra mỗi khi tôi truy cập vào một biến mới.


2
Tôi nghĩ rằng điều đó sẽ dẫn đến kiểm tra ít null hơn, bởi vì bạn chỉ phải kiểm tra xem bạn có thấy <T> không và không phải lo lắng về các loại còn lại.
aochagavia

1
@svick Maybe<T>phải cho phép nulldưới dạng giá trị, vì giá trị có thể không tồn tại. Nếu tôi có Maybe<MyClass>và nó không có giá trị, trường giá trị phải chứa tham chiếu null. Không có gì khác cho nó là an toàn có thể kiểm chứng.
mgw854

1
@ mgw854 Chắc chắn là có. Trong ngôn ngữ OO, Maybecó thể là một lớp trừu tượng, với hai lớp kế thừa từ nó: Some(có một trường cho giá trị) và None(không có trường đó). Bằng cách đó, giá trị là không bao giờ null.
Svick

6
Với "không có giá trị" theo mặc định và Có thể <T> bạn có thể chắc chắn rằng một số biến luôn chứa các đối tượng. Cụ thể, tất cả các biến không có thể <T>
aochagavia

3
@ mgw854 Điểm của sự thay đổi này sẽ là tăng sức mạnh biểu cảm cho nhà phát triển. Ngay bây giờ, nhà phát triển luôn phải giả định rằng tham chiếu hoặc con trỏ có thể là null và cần kiểm tra để đảm bảo có giá trị sử dụng được. Bằng cách thực hiện thay đổi này, bạn cung cấp cho nhà phát triển sức mạnh để nói rằng anh ta thực sự cần một giá trị hợp lệ và kiểm tra trình biên dịch để đảm bảo giá trị hợp lệ được thông qua. Nhưng vẫn cung cấp tùy chọn cho nhà phát triển, để chọn tham gia và không có giá trị nào được thông qua.
Euphoric

1

Khái niệm về nullcó thể dễ dàng bắt nguồn từ C nhưng đó không phải là vấn đề.

Ngôn ngữ lựa chọn hàng ngày của tôi là C # và tôi sẽ giữ nullmột sự khác biệt. C # có hai loại, giá trịtham chiếu . Giá trị không bao giờ có thể null, nhưng đôi khi tôi muốn có thể bày tỏ rằng không có giá trị nào là hoàn toàn tốt. Để làm điều này, C # sử dụng Nullablecác loại vì vậy intsẽ là giá trị và int?giá trị nullable. Đây là cách tôi nghĩ rằng các loại tài liệu tham khảo nên làm việc là tốt.

Xem thêm: Tham khảo Null có thể không phải là một lỗi :

Tài liệu tham khảo Null rất hữu ích và đôi khi không thể thiếu (xem xét có bao nhiêu rắc rối nếu bạn có thể hoặc không thể trả về một chuỗi trong C ++). Lỗi thực sự không nằm ở sự tồn tại của các con trỏ null, mà là cách hệ thống xử lý chúng. Thật không may, hầu hết các ngôn ngữ (C ++, Java, C #) không xử lý chúng một cách chính xác.


0

Tôi nghĩ điều này là do lập trình chức năng quan tâm nhiều đến các loại , đặc biệt là các loại kết hợp các loại khác (bộ dữ liệu, chức năng như loại hạng nhất, đơn nguyên, v.v.) so với lập trình hướng đối tượng (hoặc ít nhất là ban đầu đã làm).

Các phiên bản hiện đại của ngôn ngữ lập trình mà tôi nghĩ bạn đang nói đến (C ++, C #, Java) đều dựa trên các ngôn ngữ không có bất kỳ hình thức lập trình chung nào (C, C # 1.0, Java 1). Không có điều đó, bạn vẫn có thể nướng một số loại khác biệt giữa các đối tượng nullable và không nullable vào ngôn ngữ (như tài liệu tham khảo C ++, không thể null, nhưng cũng bị giới hạn), nhưng nó ít tự nhiên hơn.


Tôi nghĩ trong trường hợp lập trình chức năng, đó là trường hợp của FP không có kiểu tham chiếu hoặc kiểu con trỏ. Trong FP mọi thứ đều là một giá trị. Và nếu bạn có một loại con trỏ, sẽ dễ dàng nói "con trỏ không là gì".
Euphoric

0

Tôi nghĩ lý do cơ bản là tương đối ít kiểm tra null được yêu cầu để làm cho một chương trình "an toàn" chống tham nhũng dữ liệu. Nếu một chương trình cố gắng sử dụng nội dung của một phần tử mảng hoặc vị trí lưu trữ khác được cho là đã được viết với một tham chiếu hợp lệ nhưng không, kết quả trong trường hợp tốt nhất là ngoại lệ sẽ bị ném. Lý tưởng nhất, ngoại lệ sẽ chỉ ra chính xác nơi xảy ra sự cố, nhưng điều quan trọng là một loại ngoại lệ nào đó được đưa ra trước khi tham chiếu null được lưu trữ ở đâu đó có thể gây ra hỏng dữ liệu. Trừ khi một phương thức lưu trữ một đối tượng mà không cố gắng sử dụng nó theo cách nào đó trước tiên, một nỗ lực sử dụng một đối tượng sẽ - trong và chính nó - tạo thành một "kiểm tra null" các loại.

Nếu ai đó muốn đảm bảo rằng một tham chiếu null xuất hiện ở nơi không nên gây ra một ngoại lệ cụ thể nào khác NullReferenceException, thì thường sẽ cần phải bao gồm các kiểm tra null ở mọi nơi. Mặt khác, chỉ đảm bảo rằng một số ngoại lệ sẽ xảy ra trước khi tham chiếu null có thể gây ra "thiệt hại" ngoài bất kỳ điều gì đã được thực hiện thường sẽ yêu cầu tương đối ít thử nghiệm - thử nghiệm thường chỉ được yêu cầu trong trường hợp đối tượng sẽ lưu trữ tham chiếu mà không cố gắng sử dụng nó tham chiếu null sẽ ghi đè lên một tham chiếu hợp lệ hoặc nó sẽ khiến mã khác hiểu sai các khía cạnh khác của trạng thái chương trình. Những tình huống như vậy tồn tại, nhưng không phải tất cả đều phổ biến; hầu hết các tài liệu tham khảo vô tình sẽ bị bắt rất nhanhcho dù một người kiểm tra cho họ hay không .


bài này khá khó đọc (tường văn bản). Bạn có phiền chỉnh sửa ing nó thành một hình dạng tốt hơn?
gnat

1
@gnat: Có tốt hơn không?
supercat

0

" Maybe," như được viết, là một cấu trúc cấp cao hơn null. Sử dụng nhiều từ hơn để định nghĩa nó, Có thể là, "một con trỏ cho một vật hoặc một con trỏ không có gì, nhưng trình biên dịch vẫn chưa được cung cấp đủ thông tin để xác định cái nào." Điều này buộc bạn phải kiểm tra rõ ràng từng giá trị liên tục, trừ khi bạn xây dựng một đặc tả trình biên dịch đủ thông minh để theo kịp mã bạn viết.

Bạn có thể thực hiện Có thể với một ngôn ngữ có giá trị null dễ dàng. C ++ có một ở dạng boost::optional<T>. Làm cho tương đương null với Có lẽ là rất khó. Cụ thể, nếu tôi có a Maybe<Just<T>>, tôi không thể gán nó thành null (vì khái niệm như vậy không tồn tại), trong khi T**một ngôn ngữ có null rất dễ gán cho null. Điều này buộc người ta phải sử dụng Maybe<Maybe<T>>, điều này hoàn toàn hợp lệ, nhưng sẽ buộc bạn phải thực hiện nhiều kiểm tra nữa để sử dụng đối tượng đó.

Một số ngôn ngữ chức năng sử dụng Có thể vì null yêu cầu hành vi không xác định hoặc xử lý ngoại lệ, cả hai đều không phải là một khái niệm dễ dàng để ánh xạ thành các cú pháp ngôn ngữ chức năng. Có thể hoàn thành vai trò tốt hơn nhiều trong các tình huống chức năng như vậy, nhưng trong các ngôn ngữ thủ tục, null là vua. Đây không phải là vấn đề đúng sai, chỉ là vấn đề giúp cho máy tính dễ dàng thực hiện những gì bạn muốn nó làm.

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.