选择一种语言和平台并拼命地练习以满足解决问题的需要,这种方式已经一去不复返了。有时不同的钉子需要不同的锤子。
编程语言广义上可以分为命令式、声明式、动态式、函数式。
1 命令式语言
传统的命令式语言描述了执行的方式,而不是执行的内容。命令式语言从一开始就设计为提供机器码的抽象级别。
命令式语言的语句主要是操作程序的状态。面向对象的语言就是经典的状态操作器,因为它们一直在创建和改变对象。VB、C、C++、C#都是命令式语言。
这些语言都非常擅长利用类型系统和对象描述现实世界中的情形。它们都非常严格-即编译器要进行许多安全检查。安全检查(或类型合理性)表示,不能轻易地把Cow类型变成Sheep类型,所以如果在方法的签名中声明需要一个Cow类型,编译器(和运行时)就要保证不会给方法传送Sheep类型。这些语言通常有奇异的重用机制-用多态性原则编写的代码很容易抽象出来。这样其他地方的代码,从同一模块到完全不同的项目,就可以利用已编写好的代码。
2 声明式语言
声明式语言描述了执行的内容,而不是执行方式(这与命令式语言相反,命令式语言描述了如何通过程序语句操作状态)。为人所熟知的声明式语言是HTML,它描述了页面的布局、需要的字体、文本和修饰,以及在哪里显示图像。另一个经典的声明式语言是SQL,它描述了要从关系数据库提取的内容。最近的一个声明式语言例子是XAML(eXtensible Application Markup Language),它引出了一大串基于XML的声明式语言。
声明式语言擅长描述和转换数据。多年来,我们从命令式语言中调用它们来检索和操作数据。
动态语言
动态语言包括具有“动态”特性的所有语言,如后期绑定和调用、REPL(Read Eval Print Loops)、鸭子类型化(不严格的类型化,即如果对象看起来像一只鸭子,行走起来也像一只鸭子,它就一定是一只鸭子)等。
动态语言一般会尽可能把编译的操作推迟到运行时执行。
像这样的方法编译有一些有趣副作用。如果类型不需要事先完全定义(因为类型系统非常灵活),就可以编写使用严格接口(例如,COM或者其他.NET程序集)代码,使这些代码在遇到该接口的失败时有很大的灵活性。
动态语言非常适合于快速建立原型,不必事先定义类型,就可以把注意力集中在解决问题的代码上,而不是集中在实现过程中的类型约束。REPL允许逐行编写原型代码,程序中的变化会立即反映出来,而不需要把时间浪费在编译-运行-调试循环上。
Python语言是一个经典的动态语言,Ruby也是。
函数式语言
函数式语言把计算看成数学函数,它们努力避免状态操作,而主要考虑函数的结果,以此作为解决问题的基础。如果你做过微积分,那么就会很熟悉函数式编程的理论。
因为函数式编程语言一般不操作状态,所以程序中生成的副作用就小很多。这意味着这类语言一直在执行并行算法。高度并行系统的圣杯是避免重叠“无意中”的状态操作。死锁、竟态条件以及被破坏的不变量都是没有同步状态操作代码的经典问题。通过线程、共享内存以及锁来并行编程和同步都非常困难,所以为什么不一起避免?因为函数式编程语言鼓励程序员编写无状态的算法,这样编译器就可以推断出代码的自行并行性。这意味着可以利用多核处理器的强大能力,而没有管理线程、锁和共享内存的巨大负担。
函数式程序是很简洁的,与命令式语言相比,函数式语言通常需要较少的代码就可以解决问题。代码较少一般意味着bug较少,要测试的区域也较少。
使用正确的语言
有上百种语言面向.NET Framework,所以.NET开发人员有一个巨大的语言库供他们使用。.NET Framework在设计时就考虑到语言的交互操作,所以这些语言可以彼此通信,在解决编程问题时可以相互借鉴各种语言的优势。开发人员可以选择正确的语言工具来完成任务。
在语言中把每个类别的特性集混合起来是目前的一个趋势,这对程序员有好处,程序员喜欢使用的语言常会从每个类别中选择最佳特性。当前的趋势是应用程序开发人员使用命令式/动态语言,而函数式语言擅长解决特定领域的问题。
.NET可以无缝地进行语言的交互操作,因此可以使用自己喜欢的命令式语言解决大多数要解决的问题,再使用函数式语言进行数据操作,或者利用某些核心数学来解决问题。
本页共25段,1794个字符,5023 Byte(字节)