2011年4月28日 星期四

21. Scala 的企圖心,也是它的特性 --DSL

DSL 是 Domain Specific Languages 的縮寫,它指的是特殊領域的特殊語言。

「為何需要DSL?」

其實每個領域中,都有一些特殊的語言,使用特殊語言操控該領域的知識,會比較得心應手,比較直覺。
比如 game 或是 database,都有特殊的語言。SQL就是 database 的特殊語言。
以往如果要設計某個領域的特殊語言,那可要大費周章,從 parser 到 compiler 或 interpreter,很累人。

在 Scala 中,憑藉 Scala 的某些特殊語法,讓你很容易兜出個別領域的特殊語言,你可以使用這個特殊語言來進行你的工作,很妙吧!

其實,Scala 的 DSL 只是一個看起來很像該領域的語言。內在的運行方式還都是 Scala 原本的運行方式,你只要清楚 Scala 的運行方式,很容易設計不同的 DSL。但注意,這還是個假象,讓你使用起來比較容易專注在該領域中,其實內裡還是 Scala 的運作模式。

這樣的 DSL 是「Scala為內裡,DSL為外表」的寫作方式,認真說,還是遠遠不及重新設計一個專用的語言來的方便與正確。但話說回來,我們一定需要專用的語言嗎?大部分的情況,Scala 所表現出來的 DSL 已經非常夠用。 設計 DSL 的簡易性,也因此被 Scala 拿出來大肆宣傳。

20. Scala 的企圖心,也是它的特性 --Pattern Matching

在 Java 中你應該使用過 switch 這個命令,但只能比較整數類型,Java 7 會要支援 String 的比較,讓 switch 命令更加好用。但比起 Scala 的 Pattern Match,就算小巫見大巫。

Pattern match 的來源,絕對不是 switch,它其實是出自於 functional language 的特性。
回想我們寫數學函數時,常會遇到「若參數是什麼就如何,不是的話又是如何」,這引導出pattern match。

以下以費伯納西數列舉例,什麼是費伯納西數列,簡單的講就是後面的值等於前兩個值的相加,但第一個值是1,第二個值也是1。
所以費伯納西數列:1, 1, 2, 3, 5, 8, 13, ...

如何製作費伯納西數列?你在一些函數式語言中,可能會有這樣的寫法(此為虛擬碼,不要問我這是什麼語言)

function fib(1) = 1
function fib(2) = 1
function fib(n) = fib(n - 1) + fib(n-2)

第一行指令,說明fib(費伯納西)這個函數,參數 1 時,值為 1
第二行指令,說明fib(費伯納西)這個函數,參數 2 時,值為 1
第三行指令,說明fib(費伯納西)這個函數,參數 n 時,值為前面兩個值的相加

請注意!這三個指令已經將要做的事做完了,不需在那裡 loop 。
這就是函數式語言的概念,是不是很像前面用口語敘述的方式。

「這跟 pattern match 有什麼關係?」
在前面函數式語言的三個 fib 定義中,我們個別定義參數是1, 2,  n時  fib 應該如何做。
當執行時,呼叫到 fib 的函數,那時會有一個真實參數,函數式語言將會使用真實參數,逐一與各 fib 定義中的參數比對,找出符合的 fib 定義,找到後執行該 fib。
使用真實參數,逐一比較各個 function 的參數,這就是 pattern match。

「等等,這不還是與 switch 功用相類似嗎?有多稀奇?我用 switch 也可以做得到!」

嗯嗯,確實,費伯納西的參數是整數,難怪可以使用 switch 取代。
那再來另外一個例子,假設你要寫一個 greeting 的功能
1. 對於你的好友 John 要說 "John 你好"
2. 對於女士要說 "Miss " + name + " 你好"
3. 對於男士要說 "Mr " + name + " 你好"
4. 對於鴨子要說 "呱呱"

你該怎麼做?準備 「if 來 if 去」來個 if 大作戰了嗎?

看看函數式語言如何做!
function greeting("John") = "John 你好"
function greeting(isMiss(name)) = "Miss " + name + " 你好"
function greeting(isMr(name)) = "Mr " + name + " 你好"
function greeting(duck: Duck) = "呱呱"
乾淨俐落!

上面的例子也是使用參數比對來製作。從這個例子,你可看出函數式語言的參數比對,可以非常的複雜。不僅比對值,還可以比對 List,比對型態,運用非常廣泛,絕非 switch 這麼簡單的命令可比擬。

看到此,你不需急著去學習函數式語言,Scala 的 pattern match 也可做到相類似的功能,同樣可以比對值、比對 List、比對型態,也因此 pattern match 才會被列為 Scala 的超強特性。

對於 pattern match,這裡不會深入介紹,這裡只是讓大家知道有這一回事。

順帶一提 Scala 中只有 pattern match 並沒有 switch,不要誤用了。

19. Scala 的企圖心,也是它的特性 --XML處理

XML 前幾年風行極了,好像什麼東西都要與 XML 扯上一點關係才可以。

應用程式的 configuration 檔要使用 XML 的格式(實在滿坑滿谷,最簡單的就是你的 Apache Tomcat 的 web設定檔),資料交換也要使用 XML(SOAP 就是這樣來的,交換的格式就是XML),聽說本來 Java 語言的演進中,也要將 XML 處理直接放在 Java 語言中處理,雖然到現在還沒看到蹤影。

XML 筆者個人沒有特殊的好惡,但搞到沒有使用 XML 就好像不對,筆者就覺得有點走火入魔了。其實 XML 主要是給機器看的,硬要給人看,實在是有點過份、有點累。

你喜歡 Servlet 的 web.xml 設定方法?筆者是不習慣的,還好 web.xml 沒有幾層,否則光對齊 tag 就暈了。

有許多東西是好的,但要強迫用到不合適的地方就過份,相信你有看到過有十幾層以上的 XML 檔。如果那只是用在機器間的交換,那還OK,但如果那個 XML 是要讓人寫出來或是讓人讀的,那就叫整人。

這種 XML 走火入魔的方式本來也影響到 web client 與 web server 的資料交換,鼎鼎有名的Ajax,那個「x」代表的就是 XML,意思是 web client與 server 間使用 XML 來交換。

很多 programmer 看久了這種 XML 不免眼花撩亂(誰說 web client 與 server 間的資料人不用看,很多時候 programmer 可是要看它個千百回!),這時就可證明 XML 實在不適合人來看。

慢慢有人厭倦了,既有人厭倦,就有人會提出不同的作法,JSON(JavaScript Object Notation)因此現出江湖。
相對於 XML,筆者更愛 JSON,現在正常的人應該不會使用 XML 在 Ajax 的呼叫中了吧(Ajax 要改個名叫 Ajaj 嗎?!)。

啊?你現在還在使用XML?也許該順應一下潮流換換囉。現在,可能只剩下SOAP這種老古董才會堅持一定要用那麼複雜的XML格式。

JSON 的例子說明「不要以為是好東西,就要給它用的舖天蓋地」,但 XML 可也不是壞東西,大家可不要誤筆者的意思,筆者的意思是合適的地方用,不合適的地方不要用,給人看的地方,就是不合適 XML 的地方,至於合適 XML的地方,就是用在機器與機器交換的地方。

既然 XML 還是個好東西,就有需要讓它變得更好用,在 Java 中有許多關於 XML 處理的package,這裡不多談。

Scala 比 Java 更進一步,直接在語言中支援 XML,讓 XML 就像整數與字串一樣,直接在語言就處理。

「什麼是語言就直接支援 XML?」

看以下的簡單範例可以清楚點






1. 第一個指令直接使用 XML 資料,直接接指定給變數 x
    注意:XML 資料並沒有使用字串括起來,這代表 XML 是 Scala 原生支援,稱為 XML literal

2. 第二個指令抓取 x 中 "b" tag 的資料

3.第三個指令抓取 x 中 "a" tag 的資料

對於處理 XML 這樣是否非常方便,直接在語言層次支援 XML 是 Scala 的一項大特色。

18. Scala 與新的語言功能 --快速開發安全的應用程式

快速開發安全的應用程式,就是讓 programmer 可以很快做完他的工作,而且寫出來的程式碼不容易有 bug。

「寫出 bug 的程式不是 programmer 的問題嗎?」

一方面是,一方面也不是,若是環境面可以阻擋 programmer 不容易寫出壞程式碼,那不就很好嗎?
像static type與 dynamic type之爭,static type 就是可以讓一些比較粗心的 pprogrammer 不會寫出錯誤的程式碼。
另外,如 Java 移除掉 C 語言中的 pointer,與增加 garbage  ollection,也是因為這兩個特性可以大幅增加程式碼的可靠性。

Scala 有什麼方式可以增加開發速度與程式可靠性呢?

1.Scala 增加 functional 的特性:
  • 之前提到,函數式的方式著重在函數的可重複性,所以函數可以重複執行,不因情況不同而有不同的 return 值。
  • 這種特性在平行處理中非常的重要,某個函數早執行晚執行都不會讓程式有不同的情況發生,這就讓 programmer 少了仔細的需求,減少 programmer 犯錯的機會。
  • 這裡面的重點,就是多用函數,多用不可變(immutable)的資料結構(你若熟Java,就知道 String 就是不可變的資料結構),多用常數(一旦指定了值就不可再變的變數)。為何要多用不可變的呢,就是避免平行處理中的競爭問題(race condition)。
2.盡量支援平行處理:
  • Scala 想要解決平行處理的問題,希望讓我們不用太花腦筋,就可以寫出 multi-thread 的正確程式。
  • 有經驗的 programmer 看到 multi-thread 也要倒抽一口冷氣,真難,頭腦不轉清楚,一不小心,不是無法同時進行,不然就是 deadlock。
  • Scala使用 actor 的模式來解決平行處理。筆者認為,其實平行問題的範圍廣大,資料共用是最麻煩問題,actor 模式也只處理掉一點點,雖然已大幅改善寫作品質,但面對平行問題,你還是要多小心。
3.Type system:
  • Scala 的型態系統是有名的複雜,但透過 type system,compiler 會預先幫我們過濾可能的問題,預先提醒。
4.Generic(泛型):
  • Java 的 generic也就是 C++ 的 Template,就是讓一段程式碼可以適應各種不同的型態,不用因為不同的資料型態而寫出很多很像的程式碼。
  • Scala 承繼 Java 中 generic 的觀念,並且把它擴充的更完整,更嚴格,所以也更不容易寫出錯誤的程式碼,保障程式碼品質,但同樣的就更複雜,這是需要付出的代價。

17. Scala 與新的語言功能 --Meta Programming

Meta programming 這種技巧,在一些新語言上非常強調。
所謂 meta(翻成中介),其實就是以「抽象這一層」來作為處理的對象。

所謂抽象這一層,就是抽取出一層來。舉例而言,object  (或稱  instance)  的抽象那一層就叫 class。在 meta programming 中要強調的是如何處理抽象這一層。

讓我們將話講更實際一點,在一般語言中所謂的 meta programming,就是如何用程式定義(或控制) class 的行為,比如增加 class 的 field 與 method,或是用程式定義「當有程式呼叫到 class 沒有的 method 時應該如何處理」的手段。

在一些語言中,你可以動態的增加某些 class 的 method,也可以動態改變某些 class 的 method 或field,也可一次攔截該 class 中的所有 method 呼叫。甚至可以設定某些 class,若呼叫到該 class 不存在的 method,或存取到該 class 不存在的欄位,該如何處理。這都是 meta programming。

雖然 meta programming 有它的優點,但也有它的缺點。

第一個缺點就是 compiler 無法幫你做預先的篩選。比如,你指定了呼叫到不存在的 method 該處理的方式,若你真的打錯 method 名稱,此時的 compiler 能力幫你檢查。

第二個缺點就是效能,既然需要動態決定這麼多事,需要預留太多的空間,因此 compiler 勢必無法有效產出好的 bytecode,這樣一定會影響效能。

Scala 在這方面搭支援到現在是比較缺乏,現在只看到一個 Dynamic 的 class 有點類似,但還不清楚,未來我們將持續觀察。

16. Scala 與新的語言功能 --Continuation

Continuation(延續性)是可以讓程式暫時停止,然後在有需要的時候,再繼續執行。這是一個非常有用的特性,尤其運用在 web 程式的開發。

在 web 程式開發,通常一個功能需要使用者好幾次使用網頁輸入,程式執行中間需要等待使用者的回應。
我們舉一個簡單案例,在 web 製作假單申請這個功能,我們的程式流程可能定義如下(假設使用者已正常登入)

1.畫面顯示假別供使用者選擇想要申請的假別
2.畫面顯示請使用者輸入假期的區間
3.畫面回應使用者申請成功與否

這是一個非常簡單的 web 應用,但實做卻顯得繁瑣。
現在常見的作法是由畫面串連到下一個畫面。
第一個畫面輸入完畢之後,由第一個畫面串連到第二個畫面上,第二個畫面再串到第三個畫面。你的程式是否也是這樣設計?

這樣的解決方案,最麻煩的地方是流程稍微有點更動,就需要找到畫面程式加以修正,對於以後的擴充與維護造成相當大的困擾。

「那是否有比較好的方式?」

有!就是這裡所提的 continuation。

以上例而言,我們可以有一個流程程式,當流程程式執行時,先丟出第一個畫面給用戶,這時流程程式進入等待階段,等待用戶的輸入。
等待階段並不會浪費任何的 thread 與程式資源。當用戶寫完第二個畫面的資料後,會再重新啟動流程程式繼續執行,此時流程程式會依照流程的定義帶出第三個畫面給用戶輸入,依此進行。

使用 continuation 機制製作的程式,控制 web 畫面的是那個流程程式,所以畫面與畫面將不會有串連的問題,未來要修正畫面或修正流程將會非常方便。

另一個 continuation 常用的地方是 network 程式開發,網路程式通常也需要等待對方的回應,才會進行下一步的動作,所以很適合使用 continuation。

對於網路程式的開發,為讓 server 端的程式可以服務多個 client,開發方式有以下的演進

1.最早的處理方式是當有新 client 連接進來時,就 fork 出一個新的 process 來處理該 client 相關的事情,這時這個 process 只處理一個 client,程式可以使用 sequential 的方式處理,不會有問題。
這種模式稱為Process-Based的Server,早期的 Apache Server 主要的處理方式就是採取這種模式。

2.由於啟動一個 process(這是 OS 的 process),所以 server 開銷相當大,以至於 server 無法負擔太多的 client,因此修正為在同一個 process 中啟動不同的 thread 來處理個別的 client。
早期的Java network程式,這是最主要的處理方式。

3.在整臺機器中,thread 終究還是有限制的資源,為應付更多的 client,event-based 的處理模式被引進 Java 中。在 Java 我們常看到的 nio package 就是這種。nio代表 non-block IO,是當網路有資料要讀或要送時,才會回頭呼叫我們的程式,現在 Java 已經進步到 nio2。

nio模式的困難點在於你很難寫一個以 sequential 邏輯為主體的網路程式。
programmer 被迫要一次處理所有的 client,眼光就是一次處理所有的 client,需要將原來網路程式的各個步驟紀錄在不同的資料中,然後依照不同的 client 適時呼叫不同的模組,很麻煩。

為何我們不能像以前開發單一 client 的方式一樣,將處理的眼光只侷限在一個 client 就好。這就是 continuation 運用在 network 程式的方式。
當 nio callback 到我們的程式時,我們只需要該 client 所對應到的 continuation 程式叫起,然後要求該 continuation 程式繼續執行,就完成了。

以這種概念開發程式最重要的地方在於 continuation 機制的完整與否。

Continuation 可以讓我們製作一些程式時很簡單,但簡單的前提是要有好的 continuation 機制。很可惜的,在 Java 世界中現在沒有比較好 continuation 機制。
Java 世界確實存在一些 continuation 機制,但這些機制不是設定方式過於複雜就是實用性不好。有一些 web framework 號稱有 flow 或是 web flow 的機制,讓人燃起一些希望,但仔細瞭解後卻感到實用性不大。

嚴謹來說,在 Java 世界,根本沒有完整的 continuation 機制,最多只是半成品,對於有這麼龐大資源、framework 滿坑滿谷的 Java 世界,實在讓人訝異。

Continuation(延續性)很早就出現在 Smalltalk 中。由於 web 應用的特性,所以有幾個 web framework。相繼支援continuation,比如 Ruby On Rail (ROR)。

在幾年前 ROR 贏得眾人眼光之際,有人提出 Java 支援 continuation 的需求,比如有名的 Jetty Web Server 非常努力爭取。那時的 Java 團隊壓力不小,也經過許多次會議,但最後決議當然是「不支援」。

經過前篇 closure 的討論之後,我相信各位讀者都很清楚,要在 Java 這個老舊的機器加上其他強大的功能不是太容易,所以這個不支援 continuation 的決議,應該也不會太令人震驚。

各位讀者,可能會認為進到  Scala 這個世界,continuation 就自然垂手可得,但很不幸,這次你要有點失望了。
沒有說失望是因為 Scala 確實有支援,但有點失望是因為 Scala 支援 continuation 的方式令人有點不敢恭維。

Scala 的 continuation 方式有它的學理根據,它使用 CPS (Continuation Passing Style) 的方式來製作 continuation,Scala 又稱呼這種模式的 continuation 叫組合式的 continuation (Composable continuation)或 delimited continuation(意思為:一個continuation是各個段落所組成起來的)。

CPS 的意思簡單來說,就是「執行一段程式時,執行到某個地方,暫停後,將剩下的程式碼移轉出去。這個移轉出去的程式碼,在下次需要時,再將它啟動繼續執行」。
這個「暫停後,將剩下程式移轉,之後繼續執行剩下的這段程式碼」,就很像是一般我們對 continuation 的認知,可達到我們的需求。

這種 CPS 的技巧常見於函數式語言中,由於函數式語言中的函數,可以是函數組成函數,所以很容易使用函數的組合來製作這種組合式的 continuation。

Scala 基本上完全遵循函數式語言的這種模式,因此可達到 continuation 的需求。Scala 使用Responder 這個 class 輔助你撰寫 continuation,看看以下的例子:

object Test2 extends Application {
def sumup(x: int): Responder[int] = 
    for {
      val line <- ask("enter a number");
      val rest <- if (line == "") constant(x) 
                  else if (line == "?") { println("sum so far: " + x); sumup(x) }
                  else sumup(x + Integer.parseInt(line))
    } yield rest
  println("sum = " + run(sumup(0)).get)
}

for 裡面的程式碼是 continuation 的部份,可以讓你暫停程式,讀取資料後,再進行。
要注意的是,這裡的 for 並不是一般 Scala 看到 iteration 的意思,實在是令人驚訝的使用方式。

Scala 的 continuation,學理很精妙,但實用起來,國外有人說會讓人頭腦炸掉。筆者認為講得不無道理。很難要求每個人的頭腦都像 Martin 等人都有大師級的能耐。

若是你有一些專案需要使用 continuation,除非你是大師級的人物,或是很有毅力且有足夠時間的人,那你可以嘗試 Scala 的continuation。至於其他,也許再等等看以後的機會。

若你的專案很趕,那筆者建議你用原來處理流程的方式來處理你的問題(畫面串畫面不是好事,但也可以),不要過於寄望 Scala 的 continuation。

參考資料

15. Scala 與新的語言功能 --Function 與 Closure

在 imperatvie 世界中,function 與 closure 是一個很特殊的議題,尤其在 OO 的程式語言中,函數更是一個很大的衝擊。

這裡講的函數不是一般的 method,而是把函數當成一等公民,也就是 function 是 first-class 公民。

所謂一等公民是把 function 當成與資料一樣,可以設定,可以呼叫,可以傳遞,一般資料可以處理方法,function 也都要可以。

純 OO 的語言不願意接受非 object 的東西,object 通常代表是一個東西,容納資料(或叫有狀態)與行為的東西,有時,甚至資料(狀態)的含意更為強烈一些。

Function 很顯然是用來「描述行為」的,與 OO 物件「有資料有行為」的本質,兩者格格不入。有些 pure-OO 的擁護者,一看到 function,先拒絕再說。

「什麼是closure?」

Closure有人翻作閉包,closure簡單講就是一未命名的函數 (anonymous function),再加上他所閉鎖住的變數。什麼是閉鎖?有點困難是不是,沒關係,這裡暫時把 closure 當成一個沒有名稱的函數。

「Closure有什麼用處?」

用處可是很大,我們常常在 event handling 中需要一個 function 來處理該 event。

這裡舉個例子,若我們的 AP 想要攔截 mouse click,我們就需要一個 mouse click 的 event handler,最方便的作法是撰寫一個「event 的處理 function」,然後將該 function 設定給 mouse click,當用戶真的 mouse click,就直接呼叫該 function。

這是很簡單直覺的想法,但這種想法其實已經把 function 當成第一等公民來看待。

在 C 裡面可以使用 function pointer,在一些  script 語言更方便,直接指定一個 closure 給 event handler 即可。

在一些 pure-OO 語言呢?可就沒那麼簡單了,該 function 一定要把它包裝成 object 不可,所以弄了一個怪東西來代表一個簡單的概念(函數)。這種情況在 Java 同樣出現,你需要將該 function 包裝成一個 anonymous class 的 instance 才行。

有沒有感覺這是「為了 OO 而 OO」的作法。
其實,物件是人直覺的東西,功能也是人直覺的東西。為何人要這麼堅持呢?不懂!

幾年前曾出現過 Java 是否需要 closure 的爭論,Gosling (Java 的設計者) 認為 Java 並不需要closure,提出的理由是可以使用 anonymous inner class 來取代 closure。

Gosling 沒有說錯,anonymous inner class 確實可取代一部份 closure 的功能,但只是一部份,也就是 event handling 的那部份。

這種解釋與作法讓 Java 降低立即需要 closure 的壓力,直到新語言 Ruby、Groovy、Python 的挑戰出現。

在當時要求 Java 支援 closure 呼聲滿天高的時代,Microsoft 的 Anders Hejlsberg (Delphi、C#的設計者) 也曾出來消遣一下 Java 使用 anonymous internal class 作為 event handler 的這種作法。但那時由於 Micrsoft 的 C# 與 Java 戰火正烈,Microsoft 的所有作為都被是為敵意,所以 Anders Hejlsberg 的說法,被當成政治語言解讀。實在可惜,直到現在我們還繼續使用這種 anonymous inner class 作為 event handler 的跛腳解決方式。

筆者不覺得 Gosling 不明白 function 的好處與能力,但每個語言有他的特色,相信在 Gosling 的心目中,Java 的設計哲學就是簡單,使用 anonymous inner class 來作為解決方案,應該是他衡量簡單與複雜的取捨。

一個簡單的語言,與複雜功能強大語言比較,要做到相同的功能當然顯得繁瑣。但語言的好壞與否,不應該只在於功能其大,而應該與他的目標使用者(programmer)的操控能力有關。

對一個有操控能力的 programmer,功能強大的語言是他的選擇對象。但作為一個語言設計者,若希望他的語言可以吸引大部份的 programmer,簡單也可能是一個好的方式。
也許 Gosling 是這麼堅持的,堅持簡單就是美,雖然演化到現在的 Java 也已經一點都不簡單。

另一個讓 Gosling 沒有採用 closure 的因素,可能在於實現(implementation)。

各位若瞭解 JVM 與 Java classfile 的格式,你可能會驚訝 Java 之前為支援 generic 所付出的代價。

為了支援 generic,除了有一大堆 class library 需要改寫支援 generic 外,更重要的是 Java 需要翻修最底層的架構,JVM 要改、classfile 結構要改,這個工程可是大翻修,非常冒風險。由於翻動過大,雖然到了現在,我們還可發現 generic 翻修所留的痕跡,type erasure 就是一例。

在 Java 的 generic 中,有 type erasure 的問題,讀者可不要來跟我說這是特性(feature),compiler 看到與編譯出來的不同,就叫問題。
我們以下例來說明
List lst1 = new ArrayList<String>();
List lst2 = new ArrayList<Integer>();

上面的 lst1 與 lst2 經過compile後在classfile中所呈現出來的type,兩者都是ArrayList<Object>,無法清楚分辨出來。

「但從 Java source code,我們可以清楚分辨 lst1 與 lst2 不是同一個 type 啊? Java compiler 這麼差?」

這麼說都說對了,雖然從 source code 中,我們確實可以瞭解 lst1 與 lst2 型態的不同,而且 Java compiler 有能力可以分辨出這兩者的不同(否則你試著將上例中的 lst1 設定 lst2看看,看 compiler 是否允許),但產生出來的 bytecode(放在 classfile中),就是沒辦法分辨。

並不是 Java compiler 差,導致出現這個問題,問題原因出在 classfile 的格式。Java classfile 並無法容納 generic type 中 type 參數的實際資訊,因此 Java compiler 會先移除 generic type 中 type 參數的實際資訊,再產生 bytecode 儲存到 classfile中。

Java compiler 移除 generic type 中 type 參數的實際資訊,這個動作就叫做「type erasure」。

至於為何 classfile 無法容納 generic type 中 type 參數的實際資訊?很簡單,那就是會太複雜。
要容納這些資訊的話,classfile 的格式會變成太複雜,更動的幅度會過大,以至於很多工具無法好好有效的使用 classfile,原因很簡單吧。

這個簡單的因素,到現在仍繼續震撼 Java 的世界,使用 Java 泛型的 programmer 繼續受這個決定的影響。
這個因素甚至也影響到 Scala 的 programmer(你以後會知道 Scala generic 因為 type erasure 的原因, 需要花多大力氣來修正這個問題)。

你覺得 Java 開發團隊的人不願意好好處理這個問題嗎?應該不是。但筆者悲觀的認為他們不會再處理這個問題,因為影響太大,已經變得無法處理。

對於筆者而言,筆者倒希望 closure 之前沒被 Java 採納,真正的原因是,Java 團隊的人考量「簡單與實現的困難度」所得到的最合適結果。

現在最新的 Java 發展,closure 仍是大家關注的對象,雖然進度那麼令人不滿意。
Java 的 closure 叫 Lambda Expression,雖然已經是七折八扣的鳥籠 closure,但直到 Java 7 還是不支援,現在最新的消息是要到 Java 8 才支援。
由上面解釋泛型的經驗,我們知道要在既有的架構中,加上一個大的變動並不容易,所以對 Java 演進的期望值沒那麼高,但 Oracle 也讓我們等太久了。

在舊輪子開新車不容易,既然要 Java 做改進這麼的不容易,難怪就有些人提出,乾脆 Java 或 JVM 從今不再做進一步的演進,請 Oracle 推出新語言,來滿足新需求,也許更簡單俐落。

到此,讀者應該要有這樣的認識,就算 Java 或 JVM 會繼續做修正,幅度與演進速度也不容易滿足我們的願望,與其等待 Java 的演進,不如盡早找一個與你既有的 Java 程式碼可以有效共同運作的新語言。這個新語言,筆者認為 Scala 會是一個好的選擇。

關於 function 與 closure 這個需求,在 Scala 世界中的我們,可就幸福了。函數與 closure 在 Scala中都非常完整的被支援,雖然不像純函數的語言那麼令人驚豔,但夠我們享用了。