您的位置:首页 > 编程语言 > C语言/C++

利用C++、scala等语言的运算符重载功能定制领域特定语言(DSL,Domain-Specific Language )

2011-05-14 14:20 323 查看
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(实现了正则表达式)、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的语法不能很干净,比如正则表达式里面就得加入 << ,看着有点乱。这个问题运算符重载解决不了,因为运算符重载原本就没打算还有这么变态的功能。

不 过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是个很好玩的东西,而且比较实用,应该会有前途,值得关注。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: