寫在前邊:我們知道現有語言的編程范式有:過程式,面向對象,函數式,邏輯式。隨著軟件工業化程度的普及,以及軟件的復雜度越來越高,編程語言的發展歷程也是從最初的過程式(命令式)語言c,發展到以java語言為代表的面向對象編程語言。而邏輯編程語言(以prolog為代表)和函數式語言(lisp系列)還多用在學術和人工智能領域中。
近幾年,隨著多核,雲計算時代的到來。函數式編程語言逐漸浮出水面,最經典的語言以scheme、common-lisp、ml、clojure、go為代表。最近的jdk8也逐步加入了functional、closure、lambda等語法,而且scala的作者也越來越推崇編碼者以函數式語言的思維來coding。可見編程語言的發展也是滿足時代的變化不斷變化著。從其中的發展歷程中我們可以看到:技術的發展都是在圍繞著解決“軟件的復雜度”這個基本的需求而發展的。
組合手段(means of combination)
抽象手段(means of abstraction)
以上3個特性,基本上涵蓋了所有編程語言的特性,並且也是一個語言設計者從開始就要考慮的。我對這三點的理解:“基本元素”表示語言的基本符號(基本數據類型,關鍵字等)也就是詞法部分。“組合手段”利用基本元素通過組合的過程構建大型程序的手段,不同的語言提供的組合手段是不同的。“抽象手段”表示抽象,抽象是解決軟件復雜度的重要手段,讓軟件的可讀性,可擴展,可重復利用等得到提升。
下邊會從組合元素和抽象手段來對比語言特性。
java語言自稱是面向對象語言,所以比c語言更進一步,通過強大的類型系統手段來組合屬性和方法。
go語言和ML語言非常相仿,“接口”,"高階函數“,”閉包“,"duck type","返回多值”,並提供goroutine等來組合。
prolog語言完全是模式匹配的邏輯語言。他的思想基於:世間所有的定理都給予一個最簡單的定理推理而來,就像數學的基礎是“1+1=2”,然後才能推導出“萬有引力”,“相對論”等定律。
lisp方言以s-expression(著名的S表達式)來組合數據和函數。在lisp中不區分數據和函數,一切皆為數據。
題外話:lisp方言是和圖靈機的思想一脈相承的,編碼的時候完全感受不到計算機體系結構。而其他語言更多的是馮·洛伊曼的計算,存儲思想而設計,要麼是“堆棧”結構,要麼是“寄存器”結構;
以lisp為代表的函數式語言:以函數為基本和唯一的抽象;common-lisp也基於宏開發了一套object-oriented的編程方式。我比較傾向於函數式編程理念:函數的無副作用(不用考慮線程安全,特別是對於變態的Haskell),高階函數,閉包,lambda等。
弱類型語言讓我們獲取了自由(不需要類型信息),讓程序員少敲了許多鍵盤。自由是有代價的,編譯器或解釋器中內含類型推理(infer type); (類型推理是利用歸一方法,基於上下文中的變量顯式類型,操作符,返回值等信息,利用棧和逐漸替換的過程來推到出類型。) 弱類型雖然可以輕松編譯通過(或者不需要編譯而是解釋執行),但也是有類型檢查過程的,只是將此過程延遲到運行時了。所以弱類型語言結構化不強,編碼時很難確保類型無誤,IDE支持較難。但是通過一些分析器可以不斷的檢測語法,語義錯誤,相當於達到了強類型語言的IDE效果。近幾年語言的方向朝著逐漸脫離計算機體系結構,向自然語言方向在演進,程序員像藝術家一樣用代碼自由描繪。
編譯器:執行速度快。而且編譯器後端也更容易優化中間代碼,因為優化過程式一個結構化過程:往往需要遍歷整個中間代碼,整體優化代碼,提高運行效率。
runtime:一般來說解釋型語言需要在內存維護運行時上下文信息,服務於運行過程中變量的查找,綁定,scope等。 而編譯語言基於寄存器堆棧模型執行代碼,基本上數據綁定都在棧結構中完成,運行速度稍微快一些;
hotspot-jvm結合了解釋和編譯的各自優點;最先解釋執行過程,如果方法被頻繁執行,而且達到熱點(hotspot),jvm會啟動編譯過程,將次代碼編譯為native-code,然後緩存起來,下一次的調用直接執行即可。hotspot-jvm執行基於堆棧指令bytecode, 這一點也是基於跨平台的考慮而犧牲了寄存器指令; (而基於android操作系統上的dalvik虛擬機是基於寄存器指令的);
所以說,語言的設計往往是一個權衡過程;獲取的“自由”越多,"犧牲“也更大。