編程語言設計的五大陷阱
在近幾年來,編程語言的設計正在經歷著類似于“文藝復興”的過程,這么說主要是基于下面兩個事實:
1)多核技術推動著PC消費者更多的關注并行程序。
2)動態語言的性能越來越好,其性期已經可以足夠用來實現互聯網服務,并且它們正在走出“腳本語言”陰影。
這篇文章試圖收集最重要的編程語言的設計錯誤,以便讓那些程序語言設計者們在設計新型的編程語言時避免。
文章避免了一些糾纏不清的有好有壞的問題,如:動態類型或是靜態類型,同時也省略了那些看起來并不嚴重,很容易被修改的錯誤。例如,加入“參量”(ParametricType),這在Java中已經有了。Sun在發布Java 1.0版后的第八年才加入了這一功能。
1. Null指針
幾乎在所有的主流編程語言中,對一個對像的引用可能會是一個空指針,這個錯誤會引發運行時錯誤。C.A.R.Hoare最近聲明向這一“發明”負責,盡管如此,其它許多的設計者們都應該對這樣的設計受到批評。下面是C.A.RHoare的“懺悔”:我把它叫做“億萬美元錯誤”。這個空指針的發明創造來自1965年。……現在的編程語言引入了“非空引用”的聲明規格。這個方案被我在1965年給拒絕了。
其它語言,如C/C++更夸張,它們在運到這樣的錯誤時,直接Crash掉,而Java,Python和其它語言會拋出一NullPointerException異常,但問題是,這個RuntimeException可能會被幾乎所有的語句拋出。
其實,只需要一個靜態類型的語言就可以保證不會出現空指針或空引用。例如:Cyclone是一個安全的C變種,其引入了非空指針和指針運算的限制。一些語言甚至讓你根本不可能創建空指針,雖然這使得明確的指針不能行進行運算。Haskell就是這樣的一個語言,其提供了MaybeMonad,其強制程序員考慮“Null”的情形。
2. 很難解析的語法
編程語言的語法應該來自LALR或是更好的LL(1)。今天的程序員需要適當的工具來支持其開發語言,也就是我們常說的IDE,編譯器或是其它可以幫你解析程序語言的編程工具。這并不會出現在一個單一的前端。也許,多重編譯器已經被實現出來了。這可能讓我們的開始變得更容易一些。然而,我們現實中的一個反例是C++,幾乎沒有哪個C++的編譯器可以把C++這個語言完美地正確地解釋出來,而且不同C++的編譯器的行為如此的詭異。編程語法的開銷是微不足道的,程序員應該在編寫程序中享有更快速和高效的回報。
3. 未定義的語義
別在語言規格中說“實現規范”!盡可能的少使用“未定義”這樣的術語來描述語言的行為(C/C++中出現了很多undefined的行為)!黃金準則是StandardML,其是一個完整地正式的語義。C語言是這樣一個反例,其規則中有太多太多的未定義的情況。
然而,由于其廣泛使用,所以某些行為的定義已經成為了世界的共識(江湖的行規,或,潛規則)。舉個例子,在C中,整型overflow的行為是未定義的,而編譯器也是有能力推斷出“x<x+1”是否總是為真。不幸的是,這個本來是編譯器應該干的事,交給了程序員,于是在C的世界里,出現了大量的整型溢出的代碼。而當整型溢出的時候,幾乎所有的行為都是像x86處理器一樣(如:maxint+1==minint)。
明確的語義可以讓驗證和錯誤檢查更容易。雖然,軟件校驗來得比緩慢,但一定會來。我可以想像,編程語言的下一個機會將會是更容易地校驗,這可能需要十到二十年的時間,但今天開始這樣做的語言將會在那天成為世界的主流。
4. 壞的Unicode支持
程序中幾乎都要處理字符串,但別忘了并不是所有人都會使用英語來編程。今天,幾乎所有的編程語言都不支持Unicode,所以,我們只能使用ANSI的英語來編程。這個時代,程序員應該使用Unicode來編程,所以,源代碼也可以聲明其用什么來編碼。
在文本和字節序間的轉換和區分在的標準庫方面會比語言方面更是一個問題,當然,這也影響了語法。
5. 預處理器
像C++和MP4的預處理器已經被廣泛地使用著,使用預處理器更像是一種hack而不是一個干凈的解決方案。他們被用來,使用外部文件(如頭文件,但確沒有正確地模塊機制),使用條件編譯,宏替換,等。把這些功能與編程語言集成起來一起使用可以增加程序的性能和開發效率,并沒有什么不好的地方。
如果要舉一個反例,那么就是預編譯器的模塊化系統。C使用#include而C++更痛苦,因為模板需要寫一個大的頭文件,而且其會被包含在幾乎所有的其它文件中。而一個真正的模塊化的系統是不需要使用extern關鍵字,也不需要程序的鏈接,而應該是直接使用。
文章原文地址:http://beza1e1.tuxen.de/articles/proglang_mistakes.html