【delphi开源代码栏目提醒】:网学会员在delphi开源代码频道为大家收集整理了“LINQ与DLR的Expression tree(2):简介DLR - 讲义教程“提供大家参考,希望对大家有所帮助!
Disclaimer如果需要转载请先与我联系文中图片请不要直接链接 作者RednaxelaFX at rednaxelafx.iteye.com 系列文章 LINQ与DLR的Expression tree1简介LINQ与Expression tree LINQ与DLR的Expression tree2简介DLR LINQ与DLR的Expression tree3LINQ与DLR及另外两个库的AST对比 LINQ与DLR的Expression tree4创建静态类型的LINQ表达式树节点 LINQ与DLR的Expression tree5用lambda表达式表示常见控制结构 上一篇简单介绍了一下LINQ中的Expression tree是什么接下来将简单介绍一下另一个主角——DLR的状况。
先讲讲故事吧 DLR的前身——IronPython 1.x IronPython是由 Jim Hugunin在微软领导开发的一个.NET平台上的 Python实现包括了完整的编译器、执行引擎与运行时支持能够与.NET已有的库无缝整合到一起。
Python由Guido van Rossum于1990年开始开发是一种相当成熟的编程语言简洁、动态、强大。
它的标准实现也叫做CPython是用C语言编写的。
Jim Hugunin在写硕士
论文时使用Python来实现了部分功能。
1997年在他攻读博士学位时他发现Java在做简单的数值运算能达到与C一个级别的速度并萌发用Java来做一个JVM上的Python实现的想法。
经过一周的实验他觉得这个想法可行于是着手展开实际的实现工作。
这也就是JPython后改名为 Jython项目的开始。
Guido原本并不相信用Java来实现Python能够成功但Jim证明他错了。
JPython能顺利的运行Python程序而且速度也并没有想象中那么差。
考虑到当时的JVM比较慢JPython的实现已经相当不错了。
1999年Jim离开了JPython项目组加入到aspect-oriented programmingAOP的研究中并参与设计实现了 AspectJ的编译器。
当时流传Java不适合做AOP而AspectJ的成功证明他们是错的。
2000年11月一家专门制作编程语言实现和相关的开发工具的公司 ActiveState在实现Python and .NET的过程中遇到了许多挫折发表了一篇文章 Python for .NET: Lessons learned原文地址已经不存在了这个地址是一个外部备份。
其中有这么一段 Mark Hammond ActiveState Tool Corporation 写道 The speed of the current system is so low as to render the current implementation useless for anything beyond demonstration purposes. This speed problem applies to both the compiler itself and the code generated by the compiler. Given that part of the appeal of Python programming is a quick edit-compile-run cycle the speed issues severely limit the utility of Python on this platform. Some of the blame for this slow performance lies in the domain of .NET internals and Reflection::Emit but some of it is due to the simple implementation of the Python for .NET compiler. 这段评论也就成为了很长一段时间之内广泛流传的观点的来源.NET不适合实现动态语言。
主要表现为运行速度太慢与.NET平台整合度不高。
有Jython的成功作为例子大家对JVM上的动态语言已经不再抱有特别恶劣的评价但同样是通用平台同样使用虚拟机.NET却得到了相反的评价不禁让人觉得奇怪。
特别是CLR原本的一个重要卖点就是多种编程语言能够共用同一个平台能轻松的互操作为什么这些能顺利运行在.NET平台上的语言就不能包括更为动态的语言呢 2003年Jim的关注点再次回到了Python的实现上。
这次不是在JVM上而正是在受人诟病的.NET平台上。
他的动机很简单找出.NET不适合实现动态语言的原因并写一篇文章来描述这个原因。
在做了一些实验后Jim证明他原本的想法是错的——.NET很适合用于实现动态语言CLRCommon Language Runtime原本虽然是为静态类型语言设计的其与动态类型语言之间也并没有不可跨越的鸿沟。
Jim Hugunin 写道 I wanted to understand how Microsoft could have screwed up so badly that the CLR was a worse platform for dynamic languages than the JVM. My plan was to take a couple of weeks to build a prototype implementation of Python on the CLR and then to use that work to write a short pithy article called quotWhy the CLR is a terrible platform for dynamic languagesquot. My plans quickly changed as I worked on the prototype because I found that Python could run extremely well on the CLR – in many cases noticeably faster than the C-based implementation. For the standard pystone benchmark IronPython on the CLR was about 1.7x faster than the C-based implementation. Jim在2004年的PyCon上首次向外界发布了 IronPython 0.6。
此时的IronPython是以 CPLCommons Public License许可证
开源的。
随后。
在同年8月他加入了微软的CLR小组开始全职开发IronPython。
Jim做了很多努力让IronPython来到微软后仍然保持
开源最终演变为使用 Ms-PLMicrosoft Public License许可证
开源。
留意一下时间此时的.NET还是1.1版的许多现在的.NET开发者常用的基础设施都还不存在包括泛型、 轻量
代码生成Lightweight Code GenerationLCG等而且虚拟机本身的速度也还有待提高。
拥有这些新特性的.NET 2.0到2005年11月才发布。
.NET 2.0很自然的成为了IronPython继续开发的新平台。
2006年9月IronPython 1.0正式发布。
距离最初IronPython想法的萌生已经过了快3年。
IronPython小组里有许多很聪明的人想出了许多很聪明方案来解决CLR与动态语言特别是Python间的差异。
这个过程或许有趣但绝对不轻松。
再回头看看2000年ActiveState的那篇报告可以看到一个平台是如何能够受一个不好的实现而受到恶评。
当时的Python for .NET在许多重要环节都采用了实现起来比较快但对运行速度有负面影响的方式例如直接采用CPython的编译器前端、通过COM兼容层来调用System.Reflect.Emit简称SRE来生成MSIL等。
在.NET平台上managed与unmanaged之间的marshal是比较慢的让一个.NET程序的核心部分依赖于这样的互操作但却缺乏针对marshalling的优化自然会导致整个程序运行的很慢。
IronPython则走的是正常途径花的精力比Python for .NET多些完全通过C来重新实现了编译器与运行时。
在良好的设计与更新后的.NET平台的支持下IronPython比Python for .NET或者就叫Python.NET快也不足为奇。
DLR的诞生 IronPython 1.0是微软在实现动态语言平台过程中的探路石。
Jim Hugunin参与到CLR小组的目的不只是为了在.NET平台上实现一个Python更是为了让.NET成为实现动态语言的更好的平台。
以IronPython 1.0作为案例CLR小组得以了解实现一个能正常运行、达到产品质量的动态语言是怎样一个过程会遇到什么麻烦需要做些什么才能把各种奇怪的语义正确的实现出来。
在此基础上CLR小组推出了一套新的类库称为 Dynamic Language RuntimeDLR。
为了展示DLR的可行性微软会在DLR上实现4种语言 IronPython 2.x对应Python 2.5、 IronRuby 1.x对应Ruby 1.8.6、 Managed JScript对应ECMAScript v3、VBx传说中的Visual Basic 10。
DLR于 MIX 07被首度公之于世。
目前DLR仍在紧张的开发中API也还没有稳定下来。
“1.0”版的DLR预计会随着IronPython 2.0的正式发布而推出。
DLR是一个运行在CLR之上的库。
它完全是用C写的没有改变底层的执行引擎的任何部分。
这与其它平台上的一些动态语言支持相关的动向不同。
与之相对比 Parrot一开始就是设计为支持动态语言而生的最初只是Perl 6的执行引擎后来逐渐演变为一个试图支持大量动态语言的平台。
它的运行时主要是用CC89来写的。
Java平台上的 Da Vinvi Machine Project DVM则是一个直接在底层的执行引擎上做改进的方案。
也称为Multi-Language Virtual MachineMLVM。
DVM会在现有 JVM规范的基础上增加一个 invokedynamic指令的支持原本用于方法调用的JVM指令有四个invokevirtual、invokeinterface、invokespecial、invokestatic。
为此JVM本身需要做大量的修改来适应新的指令这些修改主要是用C实现的。
DVM也有一些部分会是用Java实现的主要是底层的invokedynamic指令与上层的语言结合的接口部分。
这些改变旨在提高动态语言在JVM上的运行速度属于运行时支持的部分除此之外似乎并没有计划为降低编译器编写难度而实现一些辅助用的库还好现在已经有 ASM但字节码毕竟不是那么容易对付的对象。
新语言与Java的整合方式hosting API恐怕要依靠现有的 JSR 223: Scripting for the JavaTM Platform了。
根据Jim Hugunin与John Lam在MIX 07上的讲话DLR所提供最重要的三种语言服务是 1、共享的动态类型系统 2、 宿主APIhosting API 3、可重用的编译器相关组件。
Wikipedia上的DLR条目对此有不同的表述不过本质内容是一样的 A dynamic type system to be shared by all languages utilizing the DLR services. 动态类型系统。
直接对应到上面的第1点。
Dynamic method dispatch 动态方法分发。
这个在上面没有直接的对应点。
编译器只负责编译而方法分发是运行时的工作。
所以这部分其实算是运行时库的支持。
Dynamic code generation 动态
代码生成。
这个对应到上面的第3点编译器相关组件。
Hosting API 宿主API。
直接对应到上面的第2点。
获取DLR的源码 DLR目前并没有单独发布出来而是随着IronPython、IronRuby、Silverlight Dynamic Languages SDK一起发布的。
它们的源码可以分别在下述地址找到 IronPython: Releases / Source Code IronRuby: SVN repository Silverlight Dynamic Languages SDK: Release / Source Code 更新现在 DLR已经在CodePlex上有自己的站地址是 http://www.codeplex.com/dlr。
其中的Microsoft.Scripting.Core与Microsoft.Scripting这两个项目就是DLR前者是DLR的核心后者是一些辅助设施与宿主API的实现等。
DLR提供的语言服务 动态语言的给人的第一印象就是与动态类型联系在一起。
就先从DLR的动态类型系统说起。
共享的动态类型系统 这点是DLR最能体现CLR精神的地方。
在CLR中“类型”是重要的概念不同的.NET语言共享同一套类型系统是保证语言间能够顺利的互操作的基础。
为此CLR上有专门关于类型系统的规范 通用类型系统Common Type SystemCTS与 公共语言规范Common Language SpecificationCLS。
具体规范内容可以在 EMCA-335 Common Language Infrastructure的文档中获得。
CTS定义了.NET平台上的类型规范包括值类型与引用类型、接口、类、枚举、数组、指针等的规范。
MSDN 写道 这些规范对静态类型有很重的偏向。
静态类型系统最大的特征就是一个类型的所有行为都能够静态在编译时判定。
一个类型在编译完成后就不会再发生任何改变无论是它的行为还是它的成员的个数及类型等都不会改变。
动态类型的语言则具有天生的动态性其类型系统相当有弹性在运行时既可以改变行为特征如改变方法的实现或者添加/删除方法也可以改变其成员的个数与类型。
这样的类型系统难以直接用CTS/CLS兼容的方式描述因而不容易在.NET平台上直接实现。
不仅如此流行的动态类型语言之间的类型系统都不完全兼容大家对类、方法、继承方式、动态的程序等都有各自的诠释。
有什么办法可以让它们变得互相兼容同时还要能兼顾到.NET既有的CTS/CLS呢 与其像CTS一般在类型系统层次制定一种大而全的规范来包容所有不同语言的不同类型系统DLR采取的办法是在对象的消息传递层次定义一组标准消息来解决互操作的难题。
这不是一个新想法而是一直以来面向对象系统中的核心内容。
这种简单的概念避开了显式讨论类型本身而把关注点放在了对象和消息上。
虽然各种静态和动态语言对类型本身的描述差异很大但从消息传递的层次看它们却有惊人的相似之处。
Jim Hugunin 写道 DLR的类型系统目前定义的标准消息包括在System.Scripting.Actions.StandardActionKind里 Get Set Delete Member name case-sensitivity 访问、设置、删除一个对象上的一个命名成员。
可以根据语言本身的性质选择名字的大小写敏感性。
Call / Invoke / Create argument modifiers 调用或创建对象并传递调用参数。
修饰符modifiers包括参数名、可变长参数表或者关键字参数、隐式thiscall等。
Operation operation 除了上述操作外基本上其它操作都通过这种消息来进行像是、-等运算符或者索引等。
Convert type 如果可能将一个对象转换到一个指定的静态类型。
注“目前”以2008年9月9日发布的IronPython Changeset 39444为标准。
今后仍有变动的可能。
有了这套标准消息还需要一些机制来让不同类型的对象能够响应这些消息。
在底层静态类型与动态类型的消息响应的实现机制并不一样。
静态的CLR类型的行为能够通过其类型也就是Type对象来描述所以在运行时只需要访问某个对象的Type就能够得到足够信息。
同时DLR还定义了一些Attribute让动态语言的一侧能够扩展原本的静态类型的行为与C 3/VB9的扩展方法相似这些扩展方法并不会改变原类型。
由动态语言所定义的动态类型则有另一套机制来响应标准消息。
一般这些动态类型会实现一个称为IDynamicObject的接口为所有标准消息提供自己的特殊实现。
由于每种语言能够对标准消息作出不同的响应所以得以保存自己特有的类型系统的特征。
这种通过在更抽象的层次上定义一套相对简单而灵活的协议以最大限度的支持对象行为的动态性与多样性的方式会让人联想到 CLOS的 MetaObject Protocol。
同样是定义了一套标准的协议同样能够自定义对象在运行时的行为。
事实上现在许多流行语言里的特征都可以在古老的LISP身上找到影子只是时代变迁当时的好想法终于能得到广泛推广了。
Da Vinci Machine上并没有类似的DLR的共享动态类型系统的支持而是更笼统的让语言实现自己使用其提供的动态方法分发机制来实现自己的类型系统。
相关链接 DLR Jim Hugunin: The One True Object Part 1 Jim Hugunin: The One True Object Part 2 Martin Maly: Building a DLR Language - Extension Methods 动态语言的另外一个特征是动态
代码生成。
这个特征与“动态类型”并没有直接的关系也很容易被人忽略。
动态
代码生成 Anders Hejlsberg著名的语言设计师
Delphi与C皆是他的手笔在接受 Channel 9的一个 关于C的未来发展方向的访谈时特别提到12:35开始主流动态语言中的各种特点应该分开来看人们惯于把动态语言与弱类型、静态语言与强类型当成不可分割的概念看待事实上它们并不只能这样组合在一起动态分发dynamic dispatch是动态性的重要一点而能够动态的生成强类型的程序也同等重要。
Jim Hugunin也发表了自己的看法认为一个好的嵌入式脚本语言并不一定跟动态类型有关更重要的是跟拥有方便的动态生成
代码的能力使语言便于嵌入和运行相关。
DLR正是弥补.NET Framework在动态
代码生成方面的不足的解决方案。
DLR中动态类型相关的功能与动态
代码生成的功能既可以结合在一起用于实现动态类型语言也可以彼此独立使用用于实现别的有趣功能。
原本在.NET Framework 2.0推出后有LCG/ DynamicMethod的机制来提供动态生成与执行MSIL的能力。
但是要直接使用 ILGenerator并不容易使用者必须对MSIL有清晰的认识而它相对来说抽象程度比较低会给上层开发者带来不少额外负担。
简而言之LCG虽然可以使用但不便于使用。
以LCG为实现基础DLR做了抽象程度更高的封装——DLR tree。
有一种观察各种语言的基本语言结构的数量是极其有限的。
基于这种观察可以创建出一种能够描述几乎所有语言的基本语言结构的抽象语法树。
代码生成则可以由DLR基于抽象语法树自动完成无需上层开发者操心。
这样上层开发者只要对更容易学习的DLR tree编程就能够进行动态
代码生成。
对于语言实现者来说这就意味着编译的过程从 词法分析-gt语法分析-gt语义分析-gt...中间的优化过程...-gt
代码生成 变为 词法分析-gt语法分析-gt语义分析-gt...中间的优化过程...-gtDLR tree生成 看起来步骤一样多内涵却大有不同。
我不知道别的程序员是怎么看这个问题的但我觉得
代码生成的环节是整个编译器编写过程中最棘手的一环。
前端的技术很成熟不想手写还可以用解析器生成器来帮忙
代码生成特别是对指令集很糟糕的目标做
代码生成真的是受罪????CLR的是基于栈的架构所以生成
代码相对来说难度可以说算低的了中间结果也不需要显式指定临时变量来保存只要推到求值栈上就行但如果能有办法减轻这个负担那绝对是件好事。
DLR在将DLR tree编译到MSIL时会做一些常规的优化所以语言实现者在中间的优化过程也可以省点事。
还有很重要的一点只有到DLR tree的某一个部分即将执行时它才会被编译到MSIL以后执行同一部分就不需要再次编译如果某一部分一直没被执行到则不会被编译。
也就是说不仅MSIL在编译到native code时会被JIT在DLR内部也有一层JIT机制通过延迟编译来减轻编译对性能带来的负面影响。
还有一点DLR的执行模式可以选择编译模式也可以选择解释模式。
编译模式的工作流程就如上面所说将DLR tree编译为MSIL然后执行。
解释模式则是使用DLR自带的一个解释器来遍历DLR tree并解释。
解释器的使用场景主要是特别重视启动速度的时候完成一轮编译会花去一些时间而如果执行的
代码只是很短的
代码片段只运行一次那么编译花的时间就显得不值得了。
DLR自带的解释器要追求通用性其性能可能达不到语言实现者的期待。
如果语言实现者需要更高的解释速度可以自定义解释器甚至自行编写一个解释器替换掉DLR自带的自定义或替换解释器不会影响DLR其它部分的工作。
简单的演示一个用DLR tree动态生成
代码的例子使用IronPython Changeset 39444的版本的DLR using System using System.Linq.Expressions using Microsoft.Scripting.Ast // for Utils using Ast System.Linq.Expressions.Expression namespace DlrAstTest static class Program static void Main string args var writeline typeof Console .GetMethod quotWriteLinequot new typeof string typeof object var intToString typeof int .GetMethod quotToStringquot new Type // a simple one-liner lambda: // gt Console.WriteLine quotHello worldquot // equivalent to: //lambdaBuilder.Body Expression.Call // method Expression.Constant quotHello worldquot // a more complicated case: // the lambda built below is equivalent to: //ExpressionltActiongt lambdExpression gt // for var i 0 i lt 3 i // Console.WriteLine // quotHello world: 01quot // i.ToString // 1 i quotquot : quotquot // // // make a loop variable the quotiquot var loopVariable Ast.Variable typeof int quotiquot var lambdaBuilder Utils.Lambda typeof void quotMyFuncquot Annotations.Empty // add the variable into the scope of this lambda lambdaBuilder.Locals.Add loopVariable // build the lambdas body la.
上一篇:
仓库管理系统课程设计报告
下一篇:
关于大学英语教学