Posted on 2007-03-04 18:14
canonical 阅读(1641)
评论(0) 编辑 收藏 所属分类:
设计理论
最近D语言发布了1.0版,这是一个由编译器开发者所设计的编译语言,语法类似C++, 但是针对C++的弊病作了大量修正,并增加了很多现代特征,其中还是有一些新意在其中的。http://www.digitalmars.com/d/overview.html 我对其比较感兴趣的部分是D语言明确提出的编译期运行的概念。虽然C++让大众了解了meta programming技术,很多人因此认为meta programming的威力在于类型演算,但是在我看来meta programming的真正作用在于在编译期可以“动态”产生或调整代码结构。它依赖于类型是因为我们只能利用类型来承载一些额外信息, 这无疑也是对于类型的一种滥用。在D语言中template所接受的不仅仅是类型, 或者类型的类型,它可以是任何符号.
template MixInAttr(T, char[] name){
mixin(" T _" ~ name ~";");
mixin(" T "~name~"(){ return _"~name~"; }");
mixin(" void "~name~"(T v){ _"~name~" = v;}");
}
template MixInOtherAttr(T, T v){
T _otherAttr = v;
int otherAttr(){ return _otherAttr; }
}
const int myValue = 1;
int addFunc(int x){
return x + 1;
}
class MyTest{
mixin MixInAttr!(int, "myAttr");
mixin MixInOtherAttr!(int,4);
static if(addFunc(myValue) 〉 0){
int testFunc(){ return 5;}
}
}
void main(){
auto t = new MyTest;
t.myAttr = 3;
int v = t.myAttr;
v = t.otherAttr;
t.testFunc();
}
不过现在编译期运行无疑是一个正在探索的方向, 在D语言中的使用方式并不是非常理想的, 在形式和功能实现上都存在着重大改进的可能.
在witrix平台的tpl模板语言中,我们也引入了编译期运行的概念,只是tpl的语言特征非常简单再加上xml格式特殊的规范性,编译期运行在tpl中的实现是非常直接和明确的.在tpl中定义了<cp:run〉标签,它的内容在编译期运行, 输出结果(xml字符串)将被继续编译. 在<cp:run〉中可以执行任何有效的tpl代码, 它们在编译期状态空间中运行. 例如
〈cp:run〉
〈c:forEach var="_x" items="${tagBody.children()}"〉
bla bla bla...
〈/c:forEach〉
〈/cp:run〉
在EL表达式中我们通过cp前缀实现普通调用和编译期调用的混杂.
〈cp:const class="mypkg.MyConstantClass"/〉
〈c:eval expr="${myFunc(cp:const.MY_CONST, commonVar, cp:funcInCompileTime())}" /〉
〈cp:compile test="${exprInCompileTime}"〉
any tpl ...
〈/cp:compile〉
其实当我们把改进的目光开始放到编译期的结构方面的时候, 可以做的工作是非常多的. 例如从结构上看, 继承策略相当是类结构的一种一阶替换策略.
类B(methodB) extends 类A(methodA, methodB) ==〉 类B(methodA[inA], methodB[inB])
如果我们放弃概念层面上的纠缠,而如同template那样只关注语法结构, 则可以发展出更加复杂的替换操作.
NODE_B( NODE_A( NODE_B(
SUB_NODE_A1 〉〉 SUB_NODE_A1 ==〉 SUB_NODE_A1
SUB_NODE_B11 SUB_NODE_A11 SUB_NODE_B11
SUB_NODE_A12 SUB_NODE_A12
) ) )
C++中及D语言中的template技术在某种意义上相当于是在代码结构中预留了空洞, 可以实现跨越类结构的替换填充. 只是D语言挖洞的能力无疑比C++强大的多.
如果我们考察的再细致一些, 就会发现两个语法节点的融合也是存在多种策略的.
B 〉〉 A ==〉 (remove_A, replace_A, insert_B_before_A, insert_B_after_A, insert_B_into_A, insert_A_into_B)
而通过insert_A_into_B/insert_B_into_A策略既可实现所谓的AOP intercept操作. http://canonical.javaeye.com/blog/34941 在witrix平台的BizFlow技术中, 我们通过高级的结构融合策略实现为任意实体引入流程支持. 最简单的情况下我们所需要做的工作只是增加一个语法元素
〈bizflow extends="myflow"〉
引入流程意味着对界面的一系列修正, 例如增加,删除某些菜单, 同时要增加很多流程相关函数, 对某些函数实施AOP操作, 在各处引入权限控制等等, 这些都可以通过extends操作引入.
在传统上, 编译器结构是固化的, 它所编译的代码结构是固化的, 而它所编译出的代码也是固化的, 但是现代语言的各种发展正致力于在各个层面引入动态性. 编译期运行抑或是编译期结构操纵技术的引入是在一个层面上打开了潘多拉魔盒. 它让我们看到了前所未有的技术可能性, 但它无疑也是危险的,难以控制的. 我们目前的做法是尽量克制,只在局部使用, 但我相信它在很多语言中都是可以在理论上严格定义,并精确实现的, 我们最终也能够找到合适的形式来约束它的破坏性. 在这个过程中我们需要引入更多的物理化的视角。