五個編程語言設計的失誤

 

2010年7月14日 陳皓 發表評論 閱讀評論 7,336 人閱讀   

在近幾年來,編程語言的設計正在經歷着類似於“文藝復興”的過程,這麼說主要是基於下面兩個事實:1)多核技術推動着PC消費者更多的關注並行程序。2)動態語言的性能越來越好,其性期已經可以足夠用來實現互聯網服務,並且它們正在走出“腳本語言”陰影。

這篇文章試圖收集最重要的編程語言的設計錯誤,以便讓那些程序語言設計者們在設計新型的編程語言時避免。我避免了一些糾纏不清的有好有壞的問題,如:動態類型或是靜態類型。我也省略了那些看起來並不嚴重,很容易被修改的錯誤。例如,加入“參量”(Parametric Type),這在Java中已經有了。Sun在發佈Java 1.0版後的第八年才加入了這一功能。還有一個最近的例子是 Google Go Language Design FAQ 中說到的:: “Generics may well be added at some point. We don’t feel an urgency for them, although we understand some programmers do.”

0. Null 指針

幾乎在所有的主流編程語言中,對一個對像的引用可能會是一個空指針,這個錯誤會引發運行時錯誤。 C.A.R. Hoare 最近聲明向這一“發明”負責,儘管如此,其它許多的設計者們都應該對這樣的設計受到批評。下面是 C.A.R Hoare 的“懺悔”:

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. [...] More recent programming languages like Spec# have introduced declarations for non-null references. This is the solution, which I rejected in 1965. - C.A.R. Hoare

我把它叫做“億萬美元錯誤”。這個空指針的發明創造來自1965年。…… 現在的編程語言引入了“非空引用”的聲明規格。這個方案被我在1965年給拒絕了。

其它語言,如 C/C++ 更誇張,它們在運到這樣的錯誤時,直接Crash掉,而 Java, Python 和其它語言會拋出一NullPointerException異常,但問題是,這個 RuntimeException 可能會被幾乎所有的語句拋出。其實,只需要一個靜態類型的語言就可以保證不會出現空指針或空引用。例如: Cyclone 是一個安全的C變種,其引入了非空指針和指針運算的限制。

一些語言甚至讓你根本不可能創建空指針,雖然這使得明確的指針不能行進行運算。Haskell 就是這樣的一個語言,其提供了Maybe Monad,其強制程序員考慮“Null”的情形。

1. 很難解析的語法

編程語言的語法應該來自 LALR 或是更好的 LL(1)。今天的程序員需要適當的工具來支持其開發語言,也就是我們常說的IDE,編譯器或是其它可以幫你解析程序語言的編程工具。這並不會出現在一個單一的前端。也許,多重編譯器已經被實現出來了。這可能讓我們的開始變得更容易一些。然而,我們現實中的一個反例是 C++,幾乎沒有哪個C++的編譯器可以把C++這個語言完美地正確地解釋出來,而且不同C++的編譯器的行爲如此的詭異。編程語法的開銷是微不足道的,程序員應該在編寫程序中享有更快速和高效的回報。

2. 未定義的語義

別在語言規格中說“實現規範”!儘可能的少使用“未定義”這樣的術語來描述語言的行爲(C/C++中出現了很多undefined的行爲)!黃金準則是StandardML,其是一個完整地正式的語義。C 語言是這樣一個反例,其規則中有太多太多的未定義的情況。然而,由於其廣泛使用,所以某些行爲的定義已經成爲了世界的共識(江湖的行規,或,潛規則)。 舉個例子,在C中,整型 overflow 的行爲是未定義的,而編譯器也是有能力推斷出“ x < x+1 ”是否總是爲真。不幸的是,這個本來是編譯器應該乾的事,交給了程序員,於是在C的世界裏,出現了大量的整型溢出的代碼。而當整型溢出的時候,幾乎所有的行爲都是像x86處理器一樣(如: maxint+1 == minint)。

明確的語義可以讓驗證和錯誤檢查更容易。雖然,軟件校驗來得比緩慢,但一定會來。我可以想像,編程語言的下一個機會將會是更容易地校驗,這可能需要十到二十年的時間,但今天開始這樣做的語言將會在那天成爲世界的主流。

3. 壞的Unicode 支持

程序中幾乎都要處理字符串,但別忘了並不是所有人都會使用英語來編程。今天,幾乎所有的編程語言都不支持Unicode,所以,我們只能使用ANSI的英語來編程。這個時代, 程序員應該使用Unicode 來編程,所以,源代碼也可以聲明其用什麼來編碼。

在文本和字節序間的轉換和區分在的標準庫方面會比語言方面更是一個問題,當然,這也影響了語法。讀一讀 Python 3 是怎麼解決這個問題可能會更有一些幫助。

4. 預處理器

像C++和MP4的預處理器已經被廣泛地使用着,使用預處理器更像是一種hack而不是一個乾淨的解決方案。 他們被用來,使用外部文件(如頭文件,但確沒有正確地模塊機制),使用條件編譯,宏替換,等。把這些功能與編程語言集成起來一起使用可以增加程序的性能和開發效率,並沒有什麼不好的地方。

如果要舉一個反例,那麼就是預編譯器的模塊化系統。C使用#include 而 C++ 更痛苦,因爲模板需要寫一個大的頭文件,而且其會被包含在幾乎所有的其它文件中。而一個真正的模塊化的系統是不需要使用 extern 關鍵字,也不需要程序的鏈接,而應該是直接使用。

發佈了3 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章