如果null很糟糕,那為什麼現代程式語言還要實現它?

leo199207發表於2016-06-02

網友問題

我很確定像Java 和 C# 的設計者知道 null 引用可能會導致的問題(參見這篇文章: null 引用真的是一個不好的東西嗎?) 並且,實現一個可選型別並不比 null 引用要複雜多少。

那他們為什麼要設計 null 呢?我確定對語言的創造人員和使用者(尤其是庫設計人員)來說,沒有 null 引用能推進(或強制性帶來)更好的程式碼質量。

難道僅僅是因為保守主義:其他語言是這樣的,所以我們也應該有?

Eric Lippert 的回覆

“我很確定 Java 和 C# 語言的設計者是知道 null 引用存在的一些問題。”

當然。

“實現一個可選型別並不比 null 引用複雜多少。”

恕我不能苟同! C# 2 中引入空值類的設計考慮是很複雜、有爭議並且困難的。他們讓語言和執行時的設計組進行了數月的爭論、原型實現以及其它一些工作,而事實上,空值包裝型別的語義被改變的幾乎要顛覆 C# 2.0 ,因此引起了很大爭議。

那他們為什麼還決定引入它呢?

語言的設計也就是一個在或多或少不相容的眾多目標中做選擇。我這裡簡單列舉一些可能被考慮的因素:

  • 語言特徵具有正交性普遍認為是好的。C# 有空值型別、非空值型別和空引用型別,而不存在非空引用型別,這就讓型別系統成為非正交的。
  • 要讓 C、C++和 Java 的現有使用者的容易熟悉很重要。
  • 易與 COM元件互操作很重要 。
  • 與其他 .NET 語言易互動很重要。
  • 與資料庫的能夠相互協同工作很重要。
  • 語義一致性很重要;如果 TheKingOfFrance 引用的值為空,並不意味著現在法國一定沒有國王;我只是暫且不知道是誰而已。或者也能表達“法國有國王的這個想法很荒謬”的意思,所以別問這個問題!在 C# 中,null 能夠表達以上所有的意思甚至更多,而這些意思都是有用的。
  • 效能開銷很重要。
  • 能否經過靜態分析的檢驗很重要。
  • 型別系統的一致性非常重要;我們能確定非空引用在任何情況下都不是無效的嗎?那怎麼解釋物件建構函式中引用型別的非空欄位?還有,怎麼解釋這樣一個物件在它的finalizer(物件被終結的地方),由於程式碼本應實現一個引用卻沒有導致丟擲了異常?一個取決於程式設計人員來保證安全的型別系統是很危險的。
  • 語義一致性呢?空值在被使用時能夠被傳遞,而空引用在使用時會丟擲異常。這個不一致要用哪些它帶來的益處來正名呢?
  • 我們能夠能夠實現一個不會破壞其他任何特性的特性嗎?即使可以,那又怎麼能預防以後特性的實現不會呢?
  • 你去打仗的時候是帶著你有的軍隊而不是你喜歡的。記住, C#1.0 並沒有泛型,所以討論 Maybe<T> 作為候選方案是完全不值得考慮的。如果執行團隊新增泛型,.NET 可能要走兩年下坡路,僅僅為了消除 null 引用,這值嗎?
  • 型別系統一致性呢?你也許會說 Nullable<T> 可以用於任何值型別 — 不,等等,你錯了。你總不能用 Nullable<Nullable<T>>,是吧? 如果要用這個,表示的應該是什麼意思?僅僅為了這個特徵而讓整個型別系統擁有這樣一個特例值嗎?

還有很多原因。這些決定是很麻煩的。

Doval 的最佳回覆

免責宣告: 由於我並不認識語言的設計人員,所以我的回答僅僅是我的推測。

Tony Hoare 自己說過:

我將1965年發明的 null 稱作我百萬美元的錯誤。那個時候,我正在設計第一個面嚮物件語言(ALGOLW)中的引用的綜合型別系統。我的目標是確保所有引用的使用都絕對安全,由編譯器自動執行檢查確保安全。但我無法抵擋放入空引用的誘惑,僅僅因為這個很容易實現。這個決定導致了不計其數的錯誤、漏洞和系統崩潰,在其後的四十年可能已經造成了百萬美元的損失。

說一下我的想法:

當然在那個時候設計空引用並不是一個壞主意。這可能也是它一直被延續的原因—如果快速排序的發明者得到圖靈獎是非常合適的,那麼很多人仍然不理解 null 的危害並不奇怪。也有部分是因為,不管從市場還是學習曲線上來講設計新的語言和舊的相似非常便捷。針對這點的一個案例:

“我們追隨著 C++ 的程式設計師。設法將他們中的大部分人拖向 Lisp 語言。”- Guy Steele ,Java 規範的聯合作者。(Source: http://www.paulgraham.com/icad.html

而且,當然,C++ 中有 null 是因為 C 中有, 也沒有必要去追溯 C 的歷史為什麼引入 null 。 C# 是 J++ 的替代, 微軟對 Java 的實現, 也是為了讓它取代 C++ 作為微軟開發語言的首選,所以,它可能是從任何語言的設計中引入了 null 。

另外 Hoare 的話也值得考慮一下:

程式語言整體上比曾經複雜得多:物件導向、整合,還有其他一些特性都還沒有從一個連貫、基於科學原理或正確性理論的角度認真考慮過。我最初的要求,也是我作為科學家畢生所追求的,就是使用正確性理論來收斂一個好的程式語言的設計,這樣才不會為它的使用者留下坑,程式的不同元件才能清晰正確的對應到它規格說明中的部分,這樣才能進行合理正確的思考。包括編譯器等一些工具,也必須要基於寫出正確程式碼的理論來設計。

另外,再強調一下我的看法。 Sun/Oracle 和微軟都是公司,公司的底線就是錢。包含 null 可能是利大於弊的,不然就是他們的時間太緊而不能認真推敲這個問題。這裡介紹一個由於時間緊迫而造成語言出錯的例子:

很可惜 Cloneable 失效了,但確實就這樣發生了。由於市場視窗即將關閉,原始 Java API 的開發時間非常短。最開始的 Java 團隊做得非常出色,但是並不是所有的 API 都是完美的。 Cloneable 是一個弱點,我覺得大家必須意識到它的侷限性。 – Josh Bloch (Java 大牛)

打賞支援我翻譯更多好文章,謝謝!

打賞譯者

打賞支援我翻譯更多好文章,謝謝!

任選一種支付方式

如果null很糟糕,那為什麼現代程式語言還要實現它? 如果null很糟糕,那為什麼現代程式語言還要實現它?

相關文章