JavaScript2

很久之前看到的了,想了一些问题但是一直没写出来

首先语言的变化蛮大的。这里有个疑问就是语法上很向Java靠,可是微软从来没认可过C系语言用于继承的关键字是extend。虽然这个语言被称为JavaScript,但其实它的官方名字应该是ECMAScript。而作为一个Brower上的语言,微软的支持至关重要。

当然上面的问题只是吹毛求疵。最大的问题实际上是多久之后支持JavaScript2的浏览器才能被广泛使用。B/S架构最大的好处之一就是方便的部署和升级,然而这种架构实际上是将部署升级的责任由应用开发者转移到浏览器开发者,现在有人有能力去升级世界上80%的浏览器去支持JavaScript2吗?即使微软能做到的话,那么这种情况下Avalon也就可以实现了,那微软还会支持JavaScript2吗?就算支持,以微软的性格,恐怕也会先去保证自家的Avalon吧。

转机的地方是来自Java社区的掣肘。像我原来说的,OS与AS的对立会使Avalon得不到任何Java的主流厂商的支持,那么Avalon会处于很尴尬的境地。这样JavaScript2会作为JavaScript的升级,保持现在的地位而被接受。但这种局面真的好吗?因为这像是一个双输的局面,我们得不到一个完美、优雅的RIA方案,而只是在如今的结构上修修补补尴尬度日。

Google Web Toolkit一瞥

http://code.google.com/webtoolkit/,用Java的方式来写Ajax程序。其实仅从语言的角度讲,我很喜欢js,动态类型、不封闭的类、FP等等。但是考虑到js的浏览器兼容性的问题和配套IDE等等的支持的话(虽然不可否认用FF之后js开发轻松了很多,但是那个倒霉IE)……。

一组跨平台的js ui,非常希望google能把这组ui脱离GWT放出来。开发方式,看看名字就行了(想想SWT),控件、布局、事件监听。Java的好处也全有了,类型检查、Eclipse、Junit,不过可以想象少了纯js的一些动态快感。另外就是applicationCreator的方式挺Rails的,呵呵

如果这个东西成为事实标准的话,这将是一件非常非常奇妙的事情。简单的看我们又多了一个纯java的基于Ajax的RIA解决方案,但事情比这个复杂。因为其个东西被google推出来是很奇怪的——google很有影响力,但是他不是java社区的一分子。他是想趁机混进去,还是纯粹玩玩呢?可能比较短视的看就是IBM等Java厂商对Ajax的有点漠不关心的态度(也许SOA牵扯了IBM等等太多的精力了,也没准它更希望Laszlo或Eclipse RCP,反正对比M$的Altas,我们发现Java世界没有很厂商支持的Ajax方案)让google决定自己来干——google在所有的RIA里肯定最喜欢ajax。而我第一眼看见这个就已经觉得它赢了Laszlo和Eclipse RCP了(类Laszlo、Eclipse RCP的方案里我支持M$的Avalon。但是我觉得更可能的是他们全输,因为没办法推广,OS和AS厂商的对立注定了这种结果,你能让想象Servlet输出XAML或者Windows预装Eclipse吗?)。但是如果IBM又后悔了的话,那也许我们又会面对一个分裂的世界了。

疑问是google打算投入多大的精力来维护GWT,比如我们需要Eclipse GWT Plugin,但是同样可以看到其实真正漂亮的Eclipse Plugin还是需要基金会支持的,但是这是一个来自google的方案。事实是google之前还没有掺入java社区的先例。

PS:想法挺乱,真的觉得Java社区应该有一个厂商支持的类似的东西。也许这个东西就会像其他Ajax Framework一样不温不火,纯粹是我高估了它,难说,呵呵

SCA

SCA的概念没有任何难以理解的,最主要的就是一个Service Oriented Spring,至于传输协议的透明性,那是runtime的附加能力;另外支持多语言这件事,如果C++能跑到JVM上就另当别论了,呵呵。有趣的是这两天看Celtix是发现它提到自己和Apache Tuscany整合的问题,结论是总把ESB画成一个长方形是有误导嫌疑的。

SCA的Module是可以compsite的,所以如果想象BPEL和Java的SCA Module(我的意思的Module里Component的主要成分)在不同的层次的话,那么这里就对应了比较被经常提到的SOA系统的层次。

蛮喜欢这个东西是因为是很Best-practice,比如不透明的对待local和remote,再比如IoC。略微不喜欢的就是这种通过一个规范来实现多语言版本Component的方式,COM的失败虽然和这个方式没关系,但总是不好的印象。还有从政治上说BEA和IBM联合地搞JCP也不是什么好事(虽然也未必是坏事)。

另外值得一提的就是M$的Indigo,粗略的印象里,Indigo(在CLR的帮助下)解决了SCA和SDO里除了wire的全部问题。M$一向对模式架构不关心,所以没有一个官方版本的IoC容器不值得奇怪。但是如果Indigo就是应用了OS能力的library的话,那么加一个NSpring就足以比拟SCA了

Integrate myself

用了一早上把能找的认识的人的rss都放到bloglines上了(当然还有一些fancy的东东)
开始用Google Calendar了,希望(估计也会)这个东西能和gtalk整合起来
bookmark已经都在delicious上面了,不怎么用收藏夹了(不过tag的不爽就是这东西是平面的)
豆瓣,提得挺多的了,看的书和电影都放在那里
想换个能支持定制界面的blog,这样就能把常用的功能都放到界面上,还不是太喜欢google的个性化首页(不过如果不行,我很有可能自己去花精力去写module)
我想要一个不用代理就能出国的ip

有一句话说得很好:量变引起质变。2006是integration年,说得是enterprise。个人呢?生活方式就快发生变化了,每个人,或早或晚,赶早不赶晚

python的垃圾回收机制

因为要和别人讲理,所以把这部分代码看了看。

大概说一下我的理解。python广义上的垃圾回收是用两种互补的方式实现的:首先对于每一个对象,如果它的引用计数减到0,那么它的__del__会先被调用然后被回收;python里还有一个gcmodule,这个模块虽然叫gc,但其实只是处理循环引用的问题。注释中明确地说了这个gcmodule中不会发现引用计数为0的对象。这个模块中有分代的机制。

比较java/C#和python的垃圾收集(也许是内存管理)大概有两方面区别。python和java/C#第一个区别是垃圾回收的时机。python是一旦一个对象的引用计数减为0就把这个对象回收,这里实际上是延续了C/C++的思维方式(考虑new/delete)。而java/C#都是在内存紧张才会执行整个空间上的垃圾回收。这里python看上去的好处是__del__的调用时机很明确,但是如果深入观察就会发现其实不是这样,因为你没办法控制引用计数,一旦发生循环引用你依然没办法控制__del__调用的时机(根据源码__del__还是有可能根本不被调用)。我是很怀疑python在这里把可以一起做的事情拆散了,因为完全可以在gcmodule处理循环引用的时候一并处理引用计数为零的情况。

另外的区别就是对堆的使用方式。java在创建对象时用的是很简单的方法就是从前向后不断分配――很想栈所以很快,这样在垃圾收集时,显然必要地,会对回收后还在使用的内存进行压缩。而python(至少是CPython)是继承了C的malloc,我对malloc的机制不怎么熟悉,印象中应该是空闲块list的方式吧,可能不对。加之前面回收时机的问题,这就使得python很需要一个高效的pool。

以上两种综合的机制(立即回收+malloc vs. 必要时回收+像栈一样使用,实际上有点像C/C++ vs. java了)哪个效率更高肯定是根具体实现有关的,要看具体的数据结构和算法(回收算法,pool的实现)。不过如果是java/C#对比python,那么java/C#作为大厂商们的推崇,胜出应该必然的结果。

学习了一下Python的实现

最近在网上看到这个《Python源码剖析》系列,写得很好,赞一下顺便帮着宣传http://blog.donews.com/lemur/,呵呵

顺着看下来,发现Python的实现的确有够糟糕。又引用计数来维护对象进行垃圾回收,每当一个对象的引用计数减到零时就进行回收――我怎么也觉得这是十年以前的技术了。

另外比如对于int和string类型(都是经常被大量创建和销毁的对象)使用了两种不同的缓存机制来加速。但是对于int来说,只有一定区间内(官方版本里是[-5,100)之中)的整数才能被缓存,而区间之外的整数来说都会被创建多个不同的副本。而对于string则是虽然被缓存再利用但是缓存之前字符串一定要被创建一次――也就是说这个机制只能帮助只是帮助比较操作(估计是没说清楚:-p)。本能上觉得应该有更好的做法,但也未必,因为我实际上也就看过这一种实现。

再有的发现就是一个PyPy项目http://codespeak.net/pypy/dist/pypy/doc/news.html,用Python来实现Python。从用Lisp实现Lisp开始,我就没有搞清楚这里的逻辑关系,抽空要把这个项目看一看。

程序设计语言中的动静融合

 

程序设计语言概论课的作业,1万多字,其中可能有8000多我自己写的吧。贴在这里,把摘抄不是自己写的部分删掉只留标题,所以有些段落可能不够通顺,姑且看之。Word贴过来,格式也许有问题

——————————————————-

动态语言与静态语言概述

我们常用静态语言和动态语言来划分众多的编程语言,其实这种划分并没有明确的界限。相对明确的概念是语言静态特性和动态特性的划分。动态特性是指在运行时刻的语言特性,主要依赖解释器或虚拟机,而静态特性则依赖于编译器。

(对于语言来说,动态这个词在不同的语言中有着不同的表现。对比多种编程语言我们会发现在,某些语言中,大部分关系是在运行之前确定的,即在编写代码,编译或者连接的时候就已经确定了――也就是说静态特性多一些;另一些语言则尽可能地推迟确定的时间,直到运行时才确立许多关系――动态特性多。较多采用静态特性的语言比较倾向于静态,反之就比较倾向于动态。任何一种编程语言都可以看作具有某种程度的动态特性,比如最简单是一个变量可以运行时改变它的值,可以说它也具有动态特性。而Smalltalk和Lisp这样的语言因为可以运行时改变自身的结构甚至是函数(方法)的定义,我们认为这个语言具有更强的动态特性。)――注:这段应该是抄自《程序员》,删了就不通了,留在这里

早期的程序设计语言(这里主要指高级语言)偏向于极端比如Fortran极端静态,相对的Lisp极端动态。然而下面我们会论述随着程序设计语言的发展,纯粹的静态语言和纯粹的动态语言间有一种相互吸收彼此特性的趋势。特别是随着Java之类的同时包含大量动态特性和静态特性的程序设计语言的出现,使动态语言和静态语言的界限愈发模糊。

(从Fortran -> C/C++ -> Java/C# -> Smalltalk -> Python/Ruby -> Lisp,动态特性从左到右不断加强。比如最原始的Fortran语言中没有堆栈,因此无法在运行时动态分配内存,甚至都无法进行函数递归调用;C/C++进一步,拥有堆栈,指针,能够灵活的在运行时动态生成对象(new语义)。Java和C#语言因为拥有很强的RTTI 功能,使得运行时动态识别、加载和管理类的能力大大提升。使得他们动态特性又前进了一大步。而Python和Ruby干脆可以在运行时动态改变类或是实例的结构或是定义。)――注:这段同上面注

这里我们依照习惯将Java、C#划分为静态语言,而别它们更动态的语言划分为动态语言。由此给出动态语言定义:可以在运行时刻改变变量类型和修改程序结构的程序设计语言,这里运行时刻改变变量类型主要指动态类型特性,而运行时刻修改程序结构主要指可以动态创建、删除类或函数并且可以在类中添加、删除方法或属性以及修改方法的实现;不满足这个的既是静态语言。以下我们首先讨论对这个定义中明显区分静态、动态语言的特性:静态类型和动态类型,并且简述一下静态语言和动态语言的特点;然后论述程序设计语言发展中的动静融合趋势。

静态语言

静态类型简述(删)

静态语言的特点(删)

动态语言

动态类型简述(删)

动态语言的特点

语言动态特性可以为程序提供很多好处,比如:健壮性、可移植性等等,但随着Java吸收了这些特性后,这些好处也不再是动态语言所特有的。在下一节我们会逐一讨论Java所吸收的动态特性和它们所带来的好处。而这里我们主要考虑我们定义的动态语言的特点:动态类型和运行时刻修改程序结构,给程序设计和编写所带来的好处

动态类型最基本设计哲学在于赋予程序设计最大灵活性,不在编译期给程序添加不必要限制,并认为这样可以最大程度的提高开发效率。为了说明这点,我们可以参考一下MFC的实现。MFC(出于效率考虑,但不一定必要)没有使用在现代图形界面中经常使用的多态技术――多态显然是语言动态特性,而是采用一组宏来构造消息链和消息映射等等机制。不可否认MFC从实现来看还比较优雅,但大量的宏使用使得不通过wizard来手工构造一个MFC应用几乎不可能,而且不经过深入研究很难理解MFC的工作方式。对比之下,类似wxWindows之类的图形界面框架使用多态来完成消息映射,其开发和理解难度对比MFC都很低。虽然MFC使用宏来实现主要是出于效率考虑的结果,但这恰好反映出动态语言和静态语言使用是在开发效率(程序设计的灵活性、简单性)和运行效率权衡的结果。

Java等语言吸收了大量动态特性并且被广泛使用后大大提高了人们的开发效率,但由于没有我们定义的动态语言所具备的两个主要特性:动态类型和运行时刻修改程序结构,还是给人们的开发工作带来一定的限制。作为例子我们可以参考Hibernate和Ruby on Rails中的O/R Mapping模块。如今主流的O/R Mapping框架因为需要实现对领域模型进行透明的持久化,所以需要在运行时刻对领域模型进行监视,当其数据发生变化时表示“脏数据”。然而为了不在ORM框架和领域模型之间造成不必要的耦合,也就是希望领域模型可以以POJO来实现,这就需要在运行时刻修改领域模型的结构,在其中添加必要的监视“脏数据”的方法。这里Hibernate使用CGLIB+反射机制来实现这种修改,不论从实现还是理解的难度都比Ruby那种从语言层面直接支持的方式差了许多。而实际上Ruby on Rails正是因为其大量动态特性――主要就是动态类型和运行时刻对程序结构的修改――的运用大幅度提升了开发效率才造成了对J2EE社区的极大地震动。

Java――成功的动静融合

从程序设计语言出现开始,静态语言一直是工业界的主流(Fortran、C、C++)――相对来说动态语言则是学界和Hacker的最爱(Lisp、Perl、Smalltalk)――这主要是出于效率考虑的原因,动态语言大量的运行时刻特性造成其效率不彰,在硬件比较慢的时代这是必然的结果。然而随着硬件在摩尔定律的推动下飞速前进,加之软件复杂性越来越高,那种注重运行效率而忽略开发效率的程序设计语言既失去了依存的环境也不能满足人们的需要。长期以来静态语言一直在逐渐吸收动态语言的特性:递归的引入;动态分配内存;多态等等,但这种步伐一直比较缓慢。(其中兼容性也起了一些负面的影响,就因为在对C的兼容性和效率方面投入了极大的关注,一堆天才们也只能设计出C++这种庞杂的语言,而后来的经验表明与其关注语义方面的兼容性倒不如通过对遗产系统的桥接来得直接,也更能卸掉包袱。)

对比后来的语言我们就会发现最后一个广泛流行的比较纯粹的静态语言C++太复杂了,以至于很少人可以正确使用它。即使只是以一定的运行效率的牺牲就来换取不用专家就可以实现绝对不会内存泄露的程序,我想在95年那个时候也会有很多人来做这个交易,何况动态特性还可以提供很多其它有助于开发效率的特性。所以Java的出现具有一定的必然性。

如果说语法是语言的皮,那么拔掉这层皮之后,实现看不出Java和C++有哪一点相似――Java和Smalltalk倒是更像一些――但Java在推出的时候仍然说自己是C++的更新换代,可以说Sun在这一点上做的很好,有一种假的兼容性吸引了广大C++程序员的目光。

根据我们前面的定义Java仍然是一种静态语言,但实际上Java(包括后来微软的Java实现C#、VB.NET)更像是一种动静混合的语言。它对语言动态特性的吸收可能比历史上所有静态语言吸收的综合还要多,下面我们来逐一阅览当时Java所标榜的特性,考察它们是动态或静态特性,并讨论对Java流行的影响。

我们将根据著名的”Core Java 2(7th) “中The Java “White Paper” Buzzwords部份来论述Java的特性:
简单:在做语言繁简的对比时,Java语言选取的对比标准一般是C++,对比后我们会发现我们不再有指针、头文件、结构、联合体、运算符重载(虽然必要)、虚基类、多重继承等等繁杂的概念了,Java真的很简单。遗憾的是同时我们也会发现几乎所有语言都比C++简单。另外虽然简单性不是从动态、静态角度上的特性,但简单而具有强大的表现力长久以来就是动态语言所追求的(相比动态语言Java那种每次从容器中取数据都要经过向下类型转化也就显得不那么简单了)――动态语言的始祖Lisp只用7个操作符就描述了自身。
纯粹的面向对象:Java的流行原因之一,这点的确和动静特性没关系……
分布式:Sun力推的特性,但事实证明同构平台下的分布式操作在绝大多数情况下并不需要,EJB的失败见证了这一点,而人们记住的就是Martin Fowler分布对象设计第一定律:“不要分布你的对象”。这点不是动态、静态角度上的特性,但也没给Java语言的流行带来帮助――如果不是起了反面作用。
健壮性:Java程序比C++程序更健壮,其中动态类型检查和虚拟机的内存管理量的特性功不可没――不会出现C++中的因为向下强制类型转化引发的奇怪错误,更是在理论上彻底消除了内存泄露(前提是虚拟机实现正确)。这是促使Java流行最重要的特性之一――使开发人员更关注于业务逻辑而不是时时刻刻想着堆栈――但其实动态语言从一开始就拥有这两个特性,在Lisp、Perl等等动态语言中从没见过谁关心过内存。(Lisp根本就不关心谁是冯•诺依曼)
安全:部分程度是上一点的附加特性,类似“栈溢出”等等的攻击手段被彻底杜绝了。
体系结构中立:与C++不同,Java代码被编译成byte-code,运行在虚拟机中。虚拟机有各种体系结构下的实现。但是这种体系结构中立对Java的流行有多大帮助很难说。如果说在Java刚出现C/S架构还在当道,那么Client的“一次编写,到处运行”很重要,但等到Java真正被广泛接受的98、99年,第二次浪潮已经来到B/S成为主流。所以很难说这种体系结构中立对于如今主流的Java应用还有什么帮助,可能的也就是嵌入式开发了。当然不论如何,动态语言一直是体系结构中立的,因为整个Java虚拟机的想法就是从动态语言这里发展来的,虚拟机本身就可以算是语言的动态特性。
可移植性:同上,只不过体系结构中立的同时还是OS中立(值得注意的是现在的J2EE应用已经被绑定在应用服务器中了)同样这种可移植性也是一种依赖虚拟机的动态特性。
解释型:毫无疑问,动态特性。不过对Java流行没有帮助。
高性能:(我没有考证这是从第几版开始被写入Java “White Paper”的,如果是一开始就被写入的,那么这就是个彻头彻尾的谎言。)原文的意思是说可以在运行时时刻根据程序运行的硬件环境对程序进行优化。首先可以肯定的是这也是个依赖虚拟机的动态特性;其次如果我们可以在每次部署的时候根据部署平台重新编译系统,那么可以肯定Java的byte-code肯定是要比经过编译优化的二进制代码慢的。可能有人会觉得做不到部署时重新编译,但要注意Java目前的主流应用是B/S架构的企业级应用,所以部署时重新编译是可能的;第三是这里Java有一个很大的贡献,Java的流行使虚拟机的效率在短期内大幅度提升(借助JIT等技术),并向人们证明了解释型语言的运行效率并不是想象的那么可怕。
多线程:提供并发的关键字,由虚拟机支持。较新的动态语言(Python等)都具有。
动态:主要包括动态类装载、反射,比如Java一个类的结构是由解释器在类动态装入时决定的,而在C++这样的静态语言中类在内存中的结构是编译时刻确定的,所以在类中增加一个实例变量或一种成员函数后,引用该类的所有子类都必须重新编译,否则将导致程序崩溃。这里Sun本身也承认Java是一种比C/C++动态得多的语言。原文如下”In a number of ways, Java is a more dynamic language than C or C++. It was designed to adapt to an evolving environment. Libraries can freely add new methods and instance variables without any effect on their clients. In Java, finding out run time type information is straightforward. “

总结一下我们会发现真正对Java流行起作用的语言特性(排除了分布式),除了纯粹面向对象特性(实际上打了折扣,模块、类本身和函数都不是对象,不能以一致的方式来处理,比Smalltalk、Python弱了一筹)之外,Java标榜的所有特性都可以被归为动态特性,而这些特性大部分依赖虚拟机。

如果我们对比一下主流的动态语言Perl、Python和Ruby就会发现Java除了具有静态类型特性和不能在运行时刻修改程序结构之外――后者主要指不能动态改变类、方法的声明等等,这其实是静态类型的一个副作用,比如静态类型提供编译时刻检查使程序不能调用类中还不存在的方法(实际上通过反射和CGLIB扩展字节码可以实现运行时刻一定程度修改程序结构但这种模拟方式很迂回,也不够灵活)――从哪方面看都很像一个动态语言,但也就是静态类型这一点使Java仍然是一个极为动态的静态语言。

Python、C#――进一步的动静融合

从前面所述我们可以看到,Java以静态语言为依托同时大量吸取了动态语言的优势――加之成功的运作――使其在数年间迅速发展为最为流行的程序设计语言之一。

然而自从Java诞生以来――也许是受了“Java是一种简单的语言”这句话的桎梏――从1.1到1.4 Sun除了对Java语言中的瑕疵修修补补(优化虚拟机、修改类库中一部分不好的实现等等)以外,在语言核心层面一直缺乏大的动作。只是到了C#“兵临城下”之际才在Java 5.0(这里Sun的心虚一如这个版本号)加入了泛型、自动拆装箱、元数据等特性,而这些特性也都是已经在其他语言中广泛使用的了。

Sun公司在Java发展历程中的表现告诉我们,这家公司在企图有所创新时几乎总会失败(早期Java类库的实现,Entity Bean等等),而它在软件商业领域的表现更是让我们质疑它的能力(应用服务器、集成开发环境方面的表现,我们有理由认为作为Java的发明者Sun实际可能上并没有从Java的流行中获得了太大的利益),加之JCP这个看似民主的过程存在着其他民主过程的通病――各个大利益集团相互掣肘导致的缓慢,这些因素本来完全有可能让Java这颗新星迅速陨落。但幸运的是Java发展的早期那种对微软的抵抗态度,或者说它所标榜“自由”的“宗教信仰”拯救了它自己。开源社区蓬勃发展,以及其对Java语言的大力支持,使Java仍然是今天最值得使用语言――试想如果失去众多的优秀开源产品(Eclipse、Hibernate, etc),而这些产品支持的是另一阵营(PHP、Python甚至是.NET),那将是怎样一种局面(虽然我不否认偶然中的必然性)。但需要明了的是Java在语言层面的革新动作是始终微缓,而且不值得人们报以期望。而通过下文我们会发现仅仅通过不断扩展的类库是不足以(至少是不能直观的)适应语言发展变化。

这里我们首先指出我们认为语言的发展趋势会是进一步动静融合,而从前面对Java的分析可以看到Java和主流动态语言最大的不同就是静态类型和动态类型,所以进一步动静融合的重点就在于兼取静态类型和动态类型的优势。下文将通过对Python和C#语言目前演变趋势的描述来说明这种趋势。

Python,静态类型的引入

05年年初Python的作者Guido在其blog上发表了数篇文章(Adding Optional Static Typing to Python, etc)论述了在Python中引入可选静态类型的可能性,而后在Python3.0 Plans的文档中Core language部分出现“Add optional declarations for static typing”的目标。下面我们首先叙述一下这种特性,然后讨论其引入带来的变化和好处。

Guido在其blog的文章Optional Static Typing — Stop the Flames中说明Python可能添加4种语言特性来支持可选静态类型,依次是:
参数、返回值类型定义,Argument and return type declarations
属性类型定义,Attribute declarations (maybe)
接口定义,Interface declarations
基于契约设计,Design by contract (maybe)

实际上我们注意到在目前的版本中Python类型判断运用的实际上是一种被戏称为Duck Typing的方法――Duck Typing的名字来自这句话“If it walks like a duck and talks like a duck, it must be a duck”。例如在Python中我们定义一个函数f
def f(i):
    print i.value
这样当我们调用f时传入的参数可以是任意类型,但如果运行时刻发现i不包含value的属性(it is not a duck),解释器就会抛出一个异常。这种动态类型为Python语言提供了极大的灵活性。

但是这种灵活性不是没有代价的,强大的动态类型也使Python丢失了大部分静态类型语言所拥有的便利,这包括:
文档生成,类型可以帮助我们更确切的描述参数和返回值,而动态类型导致需要大量文字来说明
IDE的帮助,现代IDE提供强大的智能完成和代码生成功能,这经常需要变量有确定的类型
优化,编译器可以利用类型信息来进行优化
反射类型信息,通过反射可以在运行时可得到函数参数和返回值的类型,利于外部库进行函数调用(特别在外部库是静态类型时,比如数据库桥,这尤为重要),尽管动态语言的反射能力一般都非常强大,但如果其本身的语义不支持函数参数返回值类型,那么也是无能为力
静态类型检查,通过早期检查提高程序的健壮性,而如今设计模式的发展已经可以很大程度上弥补静态类型所导致的紧密耦合出现。而对于大型项目,特别是多个模块同时开发的项目,静态类型接口可以作为一种有效的契约来约束各个模块的行为,而静态类型检查有效地保证了这种约束

事实上可以认为前三点只能说是引入类型带来的额外好处,而真正重要的是则是后两点。从前面论述可以看出对于大型项目失去静态类型是一件非常不利的事情,这完全可以抵消使用高灵活性动态语言所带来的生产率的优势。在此我们深化本节开始的说明:作为一门更进一步的动静融合程序设计语言最重要的特性就是兼具动态类型的灵活性和静态类型的可靠性。

这两点看似矛盾,实际上如果我们将这两点放到不同的粒度上去考虑,在一个粗粒度的级别上用静态类型描述接口,而在内部是使用动态类型编写程序,可能在将来的Python3.0中我们可以这样来编写程序:
interface IBussinessLogicFacade:
    def insertOrder(order: Order, date: Date) -> boolean: #静态类型的接口
        “insert a Order return true if succeed”

class BussinessLogic(IBussinessLogicFacade)
def insertOrder(order, date): #动态类型的实现
    …
这样我们就既能有效的利用动态语言来提高生产率又能利用静态类型来巩固程序。

但是如果我们详细阅读Guido年初的文章,我们会发现Guido最后的定稿中的可选静态类型的语言特性只是他开始提出的全部想法中很小的一个子集,大量有趣的特性没有出现在Python3.0 Plans中,这包括泛型、重载等等,而且Guido还提到Python可能不会在language core级别添加静态类型检查等等功能――静态类型可能更多的是为外围的库(比如Pychecker,一个Python程序的检查工具)提供支持,这里的静态类型可能更多地沦为一种元数据的描述手段。这里我们可以体会到Guido的小心翼翼,毕竟对于动态类型为核心的语言在其上包装一层静态类型的壳,如果一不小心就会丢失掉动态类型的好处而还要承担大量反射带来的性能损失。而且一个兼具动静融合的语言可能同时需要强大的编译器和解释器,Python社区作为一个缺少大厂商支持的社区,如果语言设计过于复杂就可能超出其能力实现的范围就可能沦为下一个Perl 6。

C#,超级编译器

微软之于JCP,与其说是专政之于民主,倒不如说是私企之于国企更为恰当。对比微软来说,JCP做对一件事几乎和做错一件事一样难,当然大部分时间他什么也不做。反之微软开发技术每次的更迭所带来的变化总是令人乍舌(Dos到Win32,Windows DNA到.NET),而这也是微软最遭开发人员诟病的地方之一。

类似的,对比属于JCP的Java和属于MS的C#(实际上也包括VB.net,简洁起见以下略去),我们同样发现C#在语言核心变更上的激进程度令人惊讶。实际上如果我们注意Java以及更早的C++就会发现这些语言都是在努力保持着语言核心的稳定和类库的激进。但是不应忘记的是与它们不同C#事实上的一种厂商专有的语言(虽然被标准化),所以从微软的角度来说变更语言核心和变更类库是可以完全从技术上考虑,这使得C#较之商业语言更像一种实验室语言――并不排除这是MS打击Java的一种战略。唯一令人担心的是语言核心如此剧烈的变更会打击开源社区的积极性(比如Mono)。

回到正题,我认为微软很久之前就注意到了动态语言的重要性。实际上远在Win32的时代,VC+VB方案流行的时候,VB就可以称为一种基于对象的动态脚本语言。而微软从COM开始就致力于不同程序设计语言间的无缝集成,到了.NET的时代从设计之初不同语言的集成就是其重要的目标,所以我们也就看到了大量的将其他程序设计语言向.NET平台迁移的项目(Perl.net, IronPython, etc)。但也许现在MS已不再热衷于动态语言与静态语言在虚拟机一级的集成了,因为从不久前微软发布了一个C#3.0的预览版本来看(实际上从C#2.0就已经开始)MS似乎想在语言层面让C#尽可能地吸收动态特性,塑造出一种可能是兼备动态类型的灵活和静态类型的可靠性的语言,而这正是我们认为的未来语言的趋势。以下简单浏览一下C#3.0的特性,并讨论一下C#和Python在动静融合方面思维方式的不同。

C#3.0最大的一个特点就是赋予了编译器强大的类型推导能力,C#3.0的大部分新特性都需要类型推导能力。比如隐式类型局部变量(implicitly typed local variable)允许我们编写这样的代码:
var i = 5;
var s = “Hello”;
var d = 1.0;
var numbers = new int[] {1, 2, 3};
var orders = new Dictionary();
这里编译器会帮助我们根据初始化语句推导出变量合适的类型,而匿名类型特性以隐式类型局部变量为基础可以产生更惊人的效果:
var p1 = new { Name = “Lawnmower”, Price = 495.00 };
var p2 = new { Name = “Shovel”, Price = 26.95 };
p2.Price = p1.Price
p1 = p2;
注意p1和p2是可以相互赋值的。可以看到这段代码很像动态语言的代码。另外C#2.0引入匿名方法,C#3.0更是引入lambda表达式(其中隐性局部变量仍然起了重要的作用)这种函数式编程的特性。这些都反映出C#在吸收动态特性方面的努力。

另外值得我们注意的是C#进行动静融合时的思维方式。为了对比我们首先看Python。实际上一般来讲我们认为静态方面的语言特性由编译器来完成,反之动态方面的语言特性由解释器(虚拟机)来完成。Python本身作为一种动态语言,它在试图吸收静态特性时首先想加强的是它的编译器。直观地想,我们会认为C#既然拥有CLR这样强大的解释器(已经在其上实现了几个动态语言,证明了其能力)那么当它吸收动态特性时理应应用这一点――如果这样做C#3.0和Python3.0可能就没什么不同了。

但事实不是这样,这里不得不承认C#3.0在这方面是另辟蹊径,C#把这些动态特性大部分推给编译器――类比C++的静态多态(泛型),利用编译器的推理能力,使程序开始运行时仍然像个静态类型语言,但在编写时可以忽略大量类型的桎梏而很像动态语言。这里最大的得利就是效率――Python、Ruby总是被人们批评为“世界上最慢的语言”,因为今天硬件的表现还不足以让我们忽略反射的损失(虽然也许10年之后谈反射的性能损失就像现在谈论虚拟机的性能损失一样)。

当然这样的实际上是“伪动态类型”的程序设计语言的灵活性到底如何还有待大范围应用后考验,但微软在这里已经走出了第一步,而C#也符合了我们开始说的实验性语言的地位。

2005-12-8