论坛首页 综合技术论坛

D语言与tpl之编译期动作

浏览 12581 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-03-04  
   最近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.iteye.com/blog/34941 在witrix平台的BizFlow技术中, 我们通过高级的结构融合策略实现为任意实体引入流程支持. 最简单的情况下我们所需要做的工作只是增加一个语法元素
 〈bizflow extends="myflow"〉
引入流程意味着对界面的一系列修正, 例如增加,删除某些菜单, 同时要增加很多流程相关函数, 对某些函数实施AOP操作, 在各处引入权限控制等等, 这些都可以通过extends操作引入.

  在传统上, 编译器结构是固化的, 它所编译的代码结构是固化的, 而它所编译出的代码也是固化的, 但是现代语言的各种发展正致力于在各个层面引入动态性. 编译期运行抑或是编译期结构操纵技术的引入是在一个层面上打开了潘多拉魔盒. 它让我们看到了前所未有的技术可能性, 但它无疑也是危险的,难以控制的. 我们目前的做法是尽量克制,只在局部使用, 但我相信它在很多语言中都是可以在理论上严格定义,并精确实现的, 我们最终也能够找到合适的形式来约束它的破坏性. 在这个过程中我们需要引入更多的物理化的视角。
   发表时间:2007-03-04  
  template MixInAttr(T, char[] name){ 
     mixin(" T _" ~ name ~";");
     mixin(" T "~name~"(){ return _"~name~"; }");
     mixin(" void "~name~"(T v){ _"~name~" = v;}");
  }  


问几个问题,
我要MixInAttr!(int, ["myAttr1", "myAttr2", ..]); 
可以?

MixInAttr!(int, string, float);
得到 int item1; string item2; float item3;
可以?

MixInAttr!( ... ) {
  maxin("mixin MixInAttr!(...);");
}

会死?

要真是那么追求code generate的能力,那就索性把整个D语言弄进编译时执行算了.
况且, 你展示的这些代码, 让我想起MACRO, C++不推荐使用MACRO就是因为它可以随意产生代码, 类型不安全, 可见性(可读)差.

我觉得C++的MP设计非常适合,
在C++0x出来之后, 就可以更好的应付MP的复杂性. (现在已经够复杂了)
你可以去看看OpenC++, 他的元编程在语法树上做文章, 灵活性最强了.  是啥下场?

在这个世界上有好多工具可以做代码生成, (生成我还可以看到整个结果, 怎么不对一目了然)
在语言中做这种事情, 一来IDE智能提示废了, 而且没有编译期调试还玩不转.
0 请登录后投票
   发表时间:2007-03-04  
关于D语言的语法问题建议自己去试验, 我并不精通。

关于tpl的编译期运行能力问题,我只能说我们需要这些能力。我们也基于这些能力作了很多工作。 并不是简单的“把整个D语言弄进编译时执行"或者 使用  MACRO就可以了。 这里的关键是如何定义合适的形式约束。OpenC++的失败是它自己的问题,而不是meta programming的问题。 就如同EJB的失败不意味着它所对应的理想的失败。
0 请登录后投票
   发表时间:2007-03-05  
我只是认为C++开发者更需要的是一大堆库,而不是一些语法上的改变。
0 请登录后投票
   发表时间:2007-03-05  
七猫 写道
我只是认为C++开发者更需要的是一大堆库,而不是一些语法上的改变。

两者都需要。
象c++Ox中的一条关于引入lambda的建议,如果不接受。像boost这样搞下去也没有活路
0 请登录后投票
   发表时间:2007-03-05  
hyf 写道
七猫 写道
我只是认为C++开发者更需要的是一大堆库,而不是一些语法上的改变。

两者都需要。
象c++Ox中的一条关于引入lambda的建议,如果不接受。像boost这样搞下去也没有活路
语法有没有,大家可以绕道走。
但没有库,就得自己写了。

其实现有的语法已经能满足大部分人需要了,对于所谓的原编程之类的,我很少看到大量使用,而且这种风格的代码的阅读性和可维护性我想大家心里都有数的。
0 请登录后投票
   发表时间:2007-03-05  
七猫 写道
hyf 写道
七猫 写道
我只是认为C++开发者更需要的是一大堆库,而不是一些语法上的改变。

两者都需要。
象c++Ox中的一条关于引入lambda的建议,如果不接受。像boost这样搞下去也没有活路
语法有没有,大家可以绕道走。
但没有库,就得自己写了。

其实现有的语法已经能满足大部分人需要了,对于所谓的原编程之类的,我很少看到大量使用,而且这种风格的代码的阅读性和可维护性我想大家心里都有数的。

对于要完成一个项目,库当然重要。
但依靠语法的逻辑抽象能力,我可以做到更细致的复用设计,有些是功能库做不到的。

MP之所没有大量使用,
一来是没有这种习惯,所以就没有需要
二来是现在的语法导致这样做 复杂、鸡肋

其实,现在的C++只要适当使用,不会降低可读性和可维护性。
0 请登录后投票
   发表时间:2007-03-05  
我觉得比较boost和qt的原代码可以得到一些启示。

到底哪种代码可读性和可维护性更好。
0 请登录后投票
   发表时间:2007-03-05  
我是说适当使用,而不是所有。

我在项目中对引入外部的模板库很谨慎,即使是STL也不是全部用上。

Boost来和Qt这些应用库很难比较,大家的方向不一样。
比方,Qt为了可用性,signal/solt是外部编译器做代码生成的。
0 请登录后投票
   发表时间:2007-03-05  
注意,某些观点我跟你一致。
我不是说库不重要,也不是想证明Boost可读性好。

我想说语法的改进一样很重要,他的能力直接影响我们如何设计库,如何复用代码。
而这次C++改良正是要降低这些复杂性。
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics