http://hi.baidu.com/atry/blog/item/c4bc96ef7a1ac7e8cf1b3ef4.html
領特定領域語言(DSL,Domain-Specific Language )是近年來的熱門話題。關於DSL,有一個趨勢就是在通用語言中整合DSL。
很多年以前,我們如果要在通用語言中使用DSL,通常需要用字串,比如作資料庫訪問,就要拼接一串SQL語句。缺點有很多:a) 不自然,特殊字元需要轉義;b) 容易留下SQL注入的漏洞;c) 缺乏語法檢查,拼錯了一個單詞還要到運行時才能知道出錯,調試起來麻煩。
不 過現在是二十一世紀了。許多語言都內建了一些DSL。比如JavaScript、ActionScript等ECMAScript語言中的新特性E4X, 可以方便的使用XML和XPath。再比如說C# 3.0中的LINQ運算式,可以寫SQL查詢。這是一個很好的現象,不過本文所講的則是“定製”DSL,可以不僅僅用上語言本身提供的DSL,還能建立自 己的DSL.
這可以靠運算子多載實現。我最早接觸運算子多載是C++,這個特性原本並未打算用來設計DSL,只是希望簡化一些日常操作的 代碼,比如字串串連。不過現在是二十一世紀了。終於出現了一群變態程式員把這個特性的潛力挖掘了出來。boost中的許多庫都用運算子多載實現了 DSL,比如Boost.Xpressive(實現了Regex)、Boost.Spirit(實現了BNF範式)、Boost.Phoenix(實現了 匿名函式宣告或者說Lambda運算式)。我自己也用運算子多載實現過static_lambda,可以把一個匿名函數變成一個靜態類型的類,用到模板參 數裡面。
根據我用過的經驗,這個技術是有用的,Boost.Xpressive和Boost.Spirit都很實用。
不過用C++運算子多載實現的DSL還是有很多致命問題的:
1. C++98的模板缺少可變數量的模板參數這個特性。
2. C++98的左值右值引用的匹配有嚴重缺陷。
3. C++編譯速度太慢。
4. C++不支援重載空格。
前兩個問題是C++98的問題,再過幾年如果C++0x普及了就解決了。
第三個問題是老大難問題,估計等到太陽變成紅色巨星的時候都未必能解決。不過C++倒是有其繼承者D語言,編譯速度奇快無比,用來定製DSL倒是不錯,只不過現在用D語言做應用開發又缺乏相應的庫、IDE啥的,因而D語言開發的項目很罕見。
第四個問題會導致DSL的文法不能很乾淨,比如Regex裡面就得加入 << ,看著有點亂。這個問題運算子多載解決不了,因為運算子多載原本就沒打算還有這麼變態的功能。
不 過C++本來定位就是有進階特性的底層語言,我們做應用開發的,大多數情況還是用更上層的語言,比如Java、C#、Ruby啥的,來連連資料庫、畫畫網 頁。C++的死活於我何相干?我關心的是應用,關心怎麼在我現在的Java項目中用上內嵌的XML、SQL之類的東西。Java寫SQL用的 PreparedStatement很噁心的一點就在於我要去數問號,設一個參數還得去數數那是第幾個問號,很讓人吐血。
所以這裡我要推薦的是scala,相容Java位元組碼,也可以產生相容.net的cli,能無縫整合到現有系統。這個scala裡面就有一個資料庫連接的庫,可以內嵌SQL語句到代碼中:
object foo extends Application {
import scala.dbc._
import scala.dbc.Syntax._
import syntax.Statement._
val db = database("jdbc:postgresql://localhost/test","myUserName","")
val res = db.executeStatement {
select fields ("name" of characterVarying(50)) from "person"
}
for(val i <- res;
val f <- i.fields) {
Console.println(f.content.sqlString)
} }
這裡面的SQL語句並非語言原生支援,而是依靠庫實現的,所以很牛叉。
不過只要搞清楚實現,就知道其實一點都不牛叉,因為scala的文法裡面可以省略訪問成員用的“.”以及函數調用的括弧,所以實際上上面那一句
select fields ("name" of characterVarying(50)) from "person"
等價於
select.fields("name" of characterVarying(50)).from("person");
這隻不過就是一段函數調用而已。
雖 然這個SQL文法scala只用了一些小把戲就實現了,不過scala是個強型別的語言,運算子多載、自動推斷類型等特性它都有,而且又沒有C++那樣的 缺陷,確實很容易實現任何DSL。此外Java社區爭論了很多年的closure它早就有了,還有一大堆函數式編程的,算是Haskell和Java的混 合體吧,既可以幹Java乾的日常工作,又有小朋友們不會用的牛叉的進階特性。所以,scala是個很好玩的東西,而且比較實用,應該會有前途,值得關注。