经常看到一些文章在谈论语言,例如“哪个语言更有前途”,“语言选择是否关键”。我是个语言粉丝,但是看到这些文章总有一些奇怪的感觉。因为在我看来,这些文章谈的东西都不是我眼中的语言——可能与国内技术环境有关,语言本身被淡化了,例如,谈语言的时候涉及更多的却是“平台”方面的内容(例如冯老大的《》)。那么我现在便来描述一下我眼中的“语言”该如何谈论吧——下次在我猛砍Java语言时也好有个参考。
语言是给人看的,人们设计出各种各样的语言,最终会通过某些工具变成机器可以执行的形式。人们设计出语言,是为了进行大规模的程序开发,否则使用机器码来0110着写,估计只有神仙才能写出如今动辄数十万数百万行高级语言的项目来——即便是“高手”也得用汇编哪。但可惜的是,如果仅仅使用汇编,估计程序员的思维永远无法跳出“子过程”这个抽象级别,什么面向对象设计,函数式编程几乎无从谈起。人们在学习和生产过程中会引发一些需求,因而需要产生一些工具来辅助学习和生产,而“语言”便是此类工具之一。只有利用高级语言,人们才能有效地把真实事件抽象成计算机这些机器盒子能认识的东西。
显然,不同的语言适合不同的领域——尤其是那些所谓的“”,因为在不同领域中所需要的思考方式可能会不一样,对于语言来说就有特定的抽象方式与之应对。不过,对于广大程序员来说接触到的更多的应该是“”,例如C,C++,Java,C#,Ruby,Python,F#……它们都是通用目的语言。对于这些语言来说,它们是为了解决广泛问题而存在的。当然,由于通用目的语言的语言特性不同,它们也是有一定“倾向性”的。例如,F#的Workflow特性尤其适合异步编程,而函数式编程语言可能更适合科学计算或金融方面的应用,因为它们和那些问题(业务)的思维方式比较接近——假如使用Java这样的面向对象语言来说可能就要使用一些奇怪的模式了。
因为语言是用来解决问题的,因此在谈论语言的时候,其实我们主要还应该把关注点放在语言抽象或描述事物(包括“思维”等等)的能力上面,以及用它们解决问题的时候是否方便,是否“舒适”——这可能有“感觉”的因素在里面,但的确也有一些客观的,可以衡量的标准在里面。例如《》一书中就提出了以下一些标准:
- 可读性:读代码的次数比写代码要多得多,可读性自然是非常重要的评判标准。例如Perl语言就比Python要难读的多,可谓是一种xx的。
- 可写性:例如,使用Fortran 77这种不支持指针和动态内存管理的语言中,实现一个二叉树结构会很困难。还有,虽然使用while可以实现任何循环需求,但是没有for语句的语言写起来便会麻烦不少。此外,表达同样的逻辑,代码是否紧凑?如C#或Java等需要相当“架子代码”的语言,同样实现面向对象编程就不如F#或Scala来的紧凑。
- 可靠性:语言特性是否易于写出正确可靠的代码,如异常处理,静态/动态类型,强/弱类型都是和可靠性有关的特性。此外,一些脚本语言,如PHP或JavaScript中经常被人诟病可靠性不佳,便是由于一些操作(如相等或相加操作)过于“宽容”,容易出错。
- 代价:例如,语言规则是否太多?是否自然?学习起来是否容易?
通俗来讲,我们考察语言,关注点应该放在它的“语言特性”上。语言特性哪里来?自然是语言制定时定下的,例如和都有其规约(Specification),其中定制了关于语言的方方面面。但是如Ruby和Python,它们都只有各自的“参考实现”(CPython及MRI),并没有明确的规约文档——有人认为这是个比较重要的问题,因此如Ruby社区便开展了项目希望定制一个严格的Ruby语言规约。
我认为,语言规约(再扩大一点,也仅仅包括其标准库)是讨论语言,比较语言的{wy}依据——这也是我在谈论语言(如讨论Java语言之低劣)的思考准则。
当然,语言设计的最终目的是让计算机进行计算,因此我们不可能回避其他方面,仅仅谈论语言规约。我这里把除了语言规约外语言实现的其他方面统称为“平台”。因此,这个平台其实包括多种东西,例如:
- 将程序文本转化为二进制形式的:编译器(包括解释器,Linker等等)。打个比方,主流C++编译器有VC++,GCC;C#编译器也有微软实现的CSC及Mono上的MCS。同样的源文件交由不同的编译器,得到的结果会有不同,而最终也会影响程序性能等因素。但是,我们可以简单认为,这些编译器最终生成的结果是符合一个统一标准的,也就是说它们得到的结果可以用相同的规则来识别与执行。
- 运行时也是平台的重要组成部分。例如,使用微软的CSC编译出的程序集可以在微软的CLR或Mono提供的运行时上执行,同样Sun的Java编译器生成的Byte Code也可以在Sun和IBM两种JVM上运行。由于运行时实现不同,所涉及的标准库也有不同,其程序执行的性能和稳定性都会有所区别。
- 在不同的执行环境下,可以利用的周边事务是不同的。例如,IronPython便非常容易和.NET程序进行互操作,而JRuby便可以利用Java平台上的各类框架。而一个C语言程序本身也是一个合法的Objective-C程序,但是在Mac OS X上编写Cocoa程序利用的也是不同的环境(不确定,求证)。
- 技术以外的方面,如社区活跃度等等。
当然,上面举的编译器和运行时都是最为典型的例子。事实上,很多平台并没有如此明显的划分,它们的编译器和运行时都是一体的。例如Python语言的实现有传统的CPython,.NET平台上的IronPython,Java平台上的Jython,以及追求比CPython更高性能与灵活性的PyPy。此外,JavaScript语言除了在各浏览器引擎中不同的原生实现外,现在又有了神奇的,可以在服务器端使用JavaScript编写高性能的服务器端程序。
当我们谈论到一门语言“能做什么”,“性能如何”时,往往就是在讨论的就不(仅仅)是语言,而是平台了。语言里的概念和平台实现并非xx相关,例如在Scala语言中,1 + 2并不是一个表达式,它其实表示的是1.+(2),也就是一个整型对象上的“加”方法的调用。但是在编译器的实现上,出于性能考虑就会尽量将其编译成原生的整数加法操作。当然,语言中的很多部分也在真切地影响其平台相关的部分,例如C语言的目标是系统语言,因此便尽可能的接近计算机体系结构,没有高级的语言特性,要把很多细节都交由程序员去控制。而如C#或Java这样的语言,从语言特性上就注定了其执行环境需要GC能力,这样对于一些空间密集型的场景可能就比不上如C语言般精细控制所带来的性能;同样,C/C++这样的语言可能并不适合高性能计算,因为它的语言设计注定了会遇上“”方面的问题,于是编译器便无法像一些无副作用的函数式编程语言那样进行自动并行,或者生成充分利用系统缓存的高性能指令。
以上,我承认语言与其平台其实有着密切联系,但是在很多情况下我们可以忽略平台而仅仅谈论语言。
例如,因为CLR和JVM的性能和可靠性是相同的(您有不同意见?嘿嘿,这里不讨论这个),所以我们便可以比较C#与Java(甚至F#与Scala);因为Rails和Django的能力不分上下,因此我们可以比较Ruby和Python语言在业务逻辑实现方面的优劣;因为它们都在JVM上执行,因此我们便可以引发Java,Scala,JRuby,Jython,Jaskell,Groovy及Clojure的混战。由于我们“求同”,那么“存异”也就有了意义,因为此时语言也是进行技术选型的重要方面了。
语言引发的争吵不计其数,这点有目共睹。我写这篇文章的目的也是希望可以减少这方面的无谓争论。例如我在猛砍Java时,有朋友会回应到:
- 做项目不能只考虑语言——没错,这并不影响我说Java语言差,我也不想以此让您来用.NET。
- JVM成熟——没错,但这并不代表Java语言就好了,您可以用Scala,Clojure等语言。
- 语言不重要,谈语言层次太低了——呃,吵不过您,我妈叫我回家吃饭,吃好饭我就洗洗睡了。
- ……
其实有时候,我也只是想单纯讨论一下语言罢了——哥谈的是语言,不是寂寞。
大腕云集的又要开始了,本次QCon更增加了语言这个主题:
以前,语言还几乎等同于平台,选择了平台也就自然而然地确定了语言。如今,在相同的平台或运行时上已经有多种成熟语言可供选择。以前,语言常被认为是一种单纯的工具。如今,语言更进一步被赋予了文化的意味。正因为如此,目前越来越多的团队在语言的选择上投入了更多的考虑,甚至已经在多种语言的混合编程上获得了成功经验。那么,您是否想了解他们为什么选择这门语言,他们在语言的设计、选择或使用方面又有哪些体会的呢?相信这部分内容可以让您满意。
继去年大受好评的“豆瓣网架构变迁”之后,洪强宁将带来Python语言在豆瓣网中的使用案例。同时,被孟岩誉为年轻一代四大高手的邓草原也会比较Scala与Erlang两者的Actor模型在生产环境下的效果。此外还有一些不知名的老外,如Paul King(Groovy{dj0}贡献者、《Groovy In Action》的作者)会讨论“动态语言的敏捷开发实践”及“Groovy中的强大功能”,JCP主席Patrick Curran也会来谈论有关一致性测试方面的话题。
现在拨打xxxx还可以享受XXXX的优惠,机不可失,失不再来,您还在等什么,还不赶快订票?
2010-02-20 21:52
哈哈,在个位慢慢看。2010-02-20 21:59
用心啦2010-02-20 23:02
说说我对DSL的理解。其实C# 3.0中就有DSL的影子:
编译后用Reflector查看,选择Optimization:.NET 2.0。对于前者,编译器生成IL代码,后者就有趣了:用System.Linq.Expressions.*的instance来描述lambda表达式。
DSL keywords no.1:description。对特定domain,构建一个可以描述它的object model,花哨的说,或装酷的说,这个object model就是metadata。compiler在这里的核心任务是:造树(创建object model instance);
DSL keywords no.2:generation。compiler的backend(或其它组件)通过爬树,将object model instance所表达的语义翻译成其它代码或底层的实现,如LINQ to xxx,MyDSL to C#,MyDSL to Java......。
知易行难,呵呵。
2010-02-20 23:13
1000个programmer眼中有10000个DSL。DSL,更准确的说,language,keywords no.0:abstraction。
2010-02-20 23:21
其实每种语言都有自己的优劣,这决定了每种语言都有自己所适用的场景和人群,或者这是语言设计者故意为之的。脱胎于Java的C#尽可能的保留了Java的诸多优势,并改进了N个方面,使其适用面和亲和力增强了很多,这是不争的事实。诚然不排除有些程序员就喜欢用Java那种风格,就好象有人就喜欢QBASIC、批处理或是PowerShell语法一样。如同爱情,这是没有道理可讲的。可更多的喷子(主原谅我在博客园用这个词)只是为了喷而喷而已。
诚然一个语言是否好用取决于很多方面,包括平台、性能以及支持库,这些东西会左右我们去选择语言(譬如写单片机程序暂时就没办法考虑C#,用批处理没办法鼓捣个有GUI的应用软件出来)。这并不是语言本身的错,事实上现在平台越来越不是问题,我看不出JVM不能跑C#的理由,只要有合适的编译器(可能要缩减一些语言特xx,如protected internal)。
2010-02-20 23:27
语言很重要,我就很喜欢javascript,虽然ie下也可以用vbscript,虽然我在asp时代一直用着vbscript,虽然我也常用vb和vba,不过当有更好的js时,vbs在我的词典中抹去是必然的。在能够选择语言的前提下,我选择我喜欢的
在不能够选择语言的情况下,我学习各种语言(cobol,pb)
2010-02-20 23:35
如果仅仅使用汇编,估计程序员的思维永远无法跳出“子过程”这个抽象级别,什么面向对象设计,函数式编程几乎无从谈起。-----------------------------
相信这群猛男吧,汇编一样可以抽象出OOP,FP的。
2010-02-20 23:49
同意,语言不是思想产生的障碍,现有思想后有语言,{zh1}才有的编译器。但语言是思想贯彻的障碍,所以人类才要发明这么多语言。
[楼主] 2010-02-20 23:50
好吧,总有猛男可以的,但是估计99.9%是不行的……
[楼主] 2010-02-20 23:57
其实我认为JVM上就跑不起来C#,因为JVM上有type erasure问题,它的泛型是假的,运行时上没有支持,所以C#上泛型的一些最常见的用法,比如泛型工厂:
T Get<T>() { return Factory<T>.Create(); }
这篇文章拖了几百年了,一直想写都懒掉了……
// 找到篇简单说明,可惜被那个啥了:
2010-02-20 23:59
于是Ruby也有正在制订中……
所以编译器是可以支持intrinsics的。提到了HotSpot中如何把Unsafe.compareAndSwapInt()看做一个intrinsic方法并在JIT编译时直接生成CAS指令来处理。
直接跑的话会跑不了嗯,规范只规定JVM在读Class文件的时候要识别Class文件中记录的泛型声明信息,但这不足以支持C# 2.0开始提供的泛型功能。间接的话当然能行,做不了的事情经常是加个间接层就能行了——实在不行,用Java实现一个CLI也是可以做到的,看看Jikes RVM、Maxine这些用Java实现的JVM就知道;人家都能用Java实现出x86的模拟器JPC了,再不行的话在JPC上面总能有办法用Java实现出CLI,而JPC是在JVM上跑的……XDD
擦除式泛型。不过“擦除”的相关定义都是Java语言层面上的。
[楼主] 2010-02-21 00:13
擦除式泛型
英文是啥亚?我刚查了一下记得应该是叫做type erasure。
你说Java可以实现JPC,所以肯定可以实现CLR,哈哈有道理。
2010-02-21 00:13
忘了说language/DSL的syntax,它的“等价”物是System.CodeDom。比较System.CodeDom.*与System.Linq.Expressions.*的内容很有趣,尽管它们并不xx重合。前者可以看作是concrete syntax tree(parse tree),后者可以看作是abstract syntax tree。(编译原理没学好,我的联想又太丰富,希望没误人子弟)
[楼主] 2010-02-21 00:15
所以编译器是可以支持intrinsics的。提到了HotSpot中如何把Unsafe.compareAndSwapInt()看做一个intrinsic方法并在JIT编译时直接生成CAS指令来处理。
.NET肯定也有这种“特殊处理”的吧,例如一些和CAS有关的方法,还比如MemoryBarrier这种。
2010-02-21 00:41
擦除式泛型
英文是啥亚?我刚查了一下记得应该是叫做type erasure。
没错。
所以编译器是可以支持intrinsics的。提到了HotSpot中如何把Unsafe.compareAndSwapInt()看做一个intrinsic方法并在JIT编译时直接生成CAS指令来处理。
.NET肯定也有这种“特殊处理”的吧,例如一些和CAS有关的方法,还比如MemoryBarrier这种。
有的。可以参考SSCLI,里FCIntrinsic*宏注册的那些方法都是都是SSCLI内认为是intrinsic的,像是Math.Sin、Math.Cos之类的都是。不过像之类的倒不算intrinsic——它并没有被inline到生成的代码里,只是像普通方法一样去调用,调用到的目标是用汇编实现的而已。
要说intrinsics的话,的。像是调用的调用点在x86上就直接被MSVC编译为int 3指令。
忘了说language/DSL的syntax,它的“等价”物是System.CodeDom。比较System.CodeDom.*与System.Linq.Expressions.*的内容很有趣,尽管它们并不xx重合。前者可以看作是concrete syntax tree(parse tree),后者可以看作是abstract syntax tree。
(编译原理没学好,我的联想又太丰富,希望没误人子弟)
这个的话我正好有个提到过,有兴趣的话参考一下?
2010-02-21 08:59
很赞同语言的选择是基于平台及应用环境的说法2010-02-21 09:01
"如C#或Java等需要相当“架子代码”的语言,同样实现面向对象编程就不如F#或Scala来的紧凑。 "这一句没看明白
2010-02-21 09:11
老赵也开始这种流行忽悠人的标题党了,不过内容是比较上档次的2010-02-21 09:22
现在拨打xxxx还可以享受XXXX的优惠,机不可失,失不再来,您还在等什么,还不赶快订票?哈哈,广告!!!博客也需要商业运作的,否则不能达到更高的高度
[楼主] 2010-02-21 09:27
"如C#或Java等需要相当“架子代码”的语言,同样实现面向对象编程就不如F#或Scala来的紧凑。 "
这一句没看明白
打个比方,C#代码:
而F#写相同的代码:
[楼主] 2010-02-21 09:29
virus唉,可惜这好像是义务的,如果卖出票子我有提成就好了,嘿嘿。
2010-02-21 09:49
哥看的不是寂寞 是知识2010-02-21 10:53
哥用的不是Java,是寂寞。2010-02-21 11:39
去iphone和mac系看看 说不定激情就来了2010-02-21 11:41
scala和closure都很强大在jvm上。。。但是需要强大的应用让更多人知道就像ruby因为rails
2010-02-21 11:44
“语言是给人看的”,这一点我就不敢苟同。2010-02-21 11:56
dreamland虽然能 但我觉得汇编这种能力 不是很纯粹.
2010-02-21 12:00
我最近也在一直整理Ruby. 相比以前熟悉的C# java Ruby在编程上自由灵活性.我只是体验在编程细节上比对变化 对于平台我还是缺乏一定概念 刚才你谈那段平台 我还不是很懂.[楼主] 2010-02-21 12:37
我一直很有激情啊,mac目前还没用出特别的激情来……
[楼主] 2010-02-21 12:38
为啥亚?
[楼主] 2010-02-21 12:39
scala和closure都很强大在jvm上。。。但是需要强大的应用让更多人知道
就像ruby因为rails
其实都有,不过都不是很大众的东西,例如Actor框架和STM。
不过像Scala它xx可以替代Java,这和Ruby倒有所不同,因为Ruby当时还不能用在其他平台上。
2010-02-21 13:22
我隐隐中觉得Jeffrey Zhao 支持汉语编程。
2010-02-21 13:37
@RednaxelaFX受教。
根据零星谣传,C# 5.0将把自己的ASTxx暴露成托管类库(我更喜欢把AST叫做object model)。我觉得xx还不够,因为MyDSL syntax与C#的syntax可能混合在一起(从可以得到些启发),如何scanner是个问题(暂时只想到这个)。
对于Common Compiler Infrastructure(CCI),与它似乎有点重合。
[楼主] 2010-02-21 14:14
我隐隐中觉得Jeffrey Zhao 支持汉语编程。
我支持易语言,当年我用他写过几个小程序,比如画面还算精美的华容道,嘿嘿。
2010-02-21 14:22
哥,真逗2010-02-21 15:00
哥写的不是程序,是寂寞!2010-02-21 15:01
园子里牛人居多,为什么不能做个NB的东西呢。2010-02-21 15:24
我看好Axum这种my syntax与C# syntax混合的DSL(ok,至于叫DSL或其它更炫的名字并不重要)。要实现一门语言的compiler,多半需要一个compiler generator(compiler compiler),在.net下,我看好(Java下,我看好)。关键是my compiler与C# 5.0提供的compiler services如何整合的问题,一团乱麻,这也是我成不了小Andsers的原因之一:)似乎在为明日担忧,俺特别喜欢来老赵这里扯蛋
[楼主] 2010-02-21 16:23
似乎在为明日担忧,俺特别喜欢来老赵这里扯蛋
欢迎。我最近有搞一个独立博客的打算,数据方面和这里会保持同步,希望到时候也多来扯扯,呵呵。
2010-02-21 17:16
似乎在为明日担忧,俺特别喜欢来老赵这里扯蛋
欢迎。我最近有搞一个独立博客的打算,数据方面和这里会保持同步,希望到时候也多来扯扯,呵呵。
嘿嘿,我一定去,俺这个菜鸟估计能把您气着了
2010-02-21 19:20
怎么扯上蛋了,呵呵 ,今天刚吃过好香啊,原来扯蛋也不错啊!2010-02-21 21:40
感觉现在混合语言蛮流行的。比如一个WEB站点,前端是JS,服务器端用C/C++,而像JAVA,.NET,PHP之类的语言起个胶水的作用把上面两者联系到一起[楼主] 2010-02-21 22:06
Marklee哪个Web站点服务器端用C/C++啊?
2010-02-21 22:13
Jeffrey Zhao有WEB IM这样做的吧,可能是我没表述清楚
2010-02-21 22:26
QCon门票好贵啊,像我等仍在读书的学生是消费不起了[楼主] 2010-02-21 23:50
Marklee嗯嗯,Facebook的聊天倒是用Erlang做的。在Web开发中需要C/C++的场景已经微乎其微了,大部分也就是做写基础结构,如存储之类的东西吧。
[楼主] 2010-02-21 23:51
EricZhang(T2噬菌体)你不是在腾迅吗?