注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

为着理想勇敢前进

 
 
 

日志

 
 

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

2008-12-13 16:37:43|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
领域特定语言(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是个很好玩的东西,而且比较实用,应该会有前途,值得关注。
  评论这张
 
阅读(681)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018