粗看上去 D 就像 C 和 C++ 。这样一来学习以及将代码移植到 D 就很容易。从 C/C++ 转向 D 应该很自然。程序员不必从头学起。
使用 D 并不意味着程序员会如 Java 或者 Smalltalk 那样被严格的限制在某一个运行时 vm (虚拟机)上。D
没有虚拟机,编译器直接生成可连接的目标文件。D 如同 C 那样被直接连接到操作系统。通常那些你熟悉的工具如 *make* 同样适用于 D 的开发。
- D 将很大程度上保留 C/C++ 的 *观感* 。它将使用相同的代数语法,绝大多数的相同表达式和语句形式,以及总体的结构。
- D 程序既可以采用 C 风格的 *函数和数据* 范式,也可以采用 C++ 风格的 *面向对象* 范式,或者它们两者的混合。
- *编译/链接/调试* 的开发模型将会被继承下来,但是把 D 编译成为字节码然后解释执行也不会有任何问题。
- *异常处理 *越来越多的使用经验显示,异常处理是比 C 传统的"出错代码/全局errno变量"模型更为高级的错误处理模型。
- *运行时类型识别* C++ 部分地实现了这个功能,而 D
更进一步。对运行时类型识别的完全支持将使垃圾收集运行的更好,会使调试器的功能更强,会使对自动持久化的支持更好等等。
- D 维持了同 *C 调用惯例* 的兼容。这样就能够使 D 程序直接访问操作系统的 API 。程序员有关现有 API
和编程范例的知识和经验可以继续在使用 D 时使用而只需付出很少的努力。
- *运算符重载* D 支持对运算符的重载,这样就可以用用户定义的类型扩展由基本类型构成的类型系统。
- *模板*模板是实现范型编程的一种手段。其他的手段包括使用宏或者采用协变数据类型。使用宏已经过时了。协变类型很直接,但是低效且缺少类型检查。C++
模板的问题是它们太复杂,同语言的语法不和谐,还有各种各样的类型转换和重载规则,等等。D 提供了一种简单得多的使用模板的方法。
- *RAII(资源获得即初始化)* RAII 技术是编写可靠软件的重要方法之一。
- *Down&dirty 编程* D 将保留 down&dirty
编程的能力,而不用采用别的语言编写的外部模块。在进行系统编程时,有时需要将一种指针转换成另一种指针,或者使用汇编语言。D
的目标不是*避免*down&dirty 编程,而是减少在进行普通程序设计时对它们的需要。
废弃的特征
- 对 C 的源码级兼容性。保留对 C 的源码级兼容的扩展已经有了(C++ 和
Objective-C)。在这方面的进一步工作受制于大量的遗留代码,已经很难对这些代码进行什么重大的改进了。
- 对 C++ 的链接兼容性。C++ 的运行时对象模型太复杂了――如果要较好的支持它,基本上就是要求 D 编译器变成一个完整的 C++
编译器了。
- C 预处理程序。宏处理是一种扩展语言的简单方法,它可以给语言加入某些语言本不支持的(对于符号调试器不可见的)特征。条件编译、使用
#include 分层的文本、宏、符号连接等,本质上构成了两种难以区分两种语言的融合体,而不是一种语言。更糟的是(或许是最好的),C
预处理程序是一种十分原始的宏语言。是停下来的时候了,看看预处理程序是用来做什么的,并将这些功能直接设计到语言内部。
- 多重继承。它是一种拥有饱受争议的价值的复杂特征。它很难用一种高效的方式实现,而且在编译器实现它时很容易出现各种 bug 。几乎所有的
MI 的功能都能够通过使用单根继承加接口和聚集的方式实现。而那些只有 MI 才能支持的功能并不能弥补它带来的副作用。
- 名字空间。当链接独立开发的代码时,可能会发生名字的冲突,名字空间就是解决这个问题的一种尝试。模块的概念更简单并且工作得更好。
- 标记名字空间。这是 C 的一个糟糕的特征,结构的标记名称位于一个同其它符号不同的符号表中。C++
试图合并标记名字空间和正常的名字空间,但同时还要维持对遗留 C 代码的向后兼容性。造成的结果是不可打印。
- 前向声明。C 编译器在语义上只知道什么东西实在词法上位于当前状态之前的。C++
进行了一点点扩展,类中的成员可以依赖于它之后声明的类成员。D
更进一步,得到了一个合情合理的结论,前向声明根本就没有存在的必要。函数可以按照一种自然的顺序定义,不用再像 C
那样为了避免前向声明而采用常用的从里到外的顺序定义。
- 包含文件。造成编译器运行缓慢的原因之一是编译每个编译单元时都需要重新解析数量巨大的头文件。包含文件的工作应该采用导入到符号表中的方式来完成。
- 在堆栈上创建对象实例。在 D
中,所有的类都通过引用来访问。这样就不需要复制构造函数、赋值运算符、复杂的析构语义以及同异常处理中的堆栈展开的相互作用。内存资源由垃圾收集程序负责释放,其他资源通过使用
D 的 RAII 特征释放。
- 三字节码和双字节码。Unicode 是未来。
- 预处理程序。现代语言不应该需要文本处理,它们应该只需要符号处理。
- 非虚成员函数。在 C++
中,由累得设计者决定一个函数是否应该是虚函数。在子类中重写一个函数而忘记在父类中将其更新为虚函数是一个常见的(并且非常难以发现的)编码错误。将所有成员函数设置为虚函数,并由编译器来判断函数是否被重写、并由此将没有被重写的函数转换为非虚函数的做法更为可靠。
- 任意长度的位字段。位字段是一种复杂、低效并且很少用到的特征。
- 支持16位计算机。D 从不考虑混合使用远/近指针和其它所有用于声称好的16位代码的机制。D
语言的设计假设目标机器至少拥有32位的平坦内存空间。D 将能够被毫无困难的移植到64位架构上。
- 对编译遍数的互相依赖。在 C++ 中,需要一个符号表和各种的预处理程序命令才能成功的解析一个源文件。这样就使预解析 C++
源码变得不可能,并且使编写代码分析程序和语法制导的编辑器的过程十分难以正确实现。
- 编译器的复杂性。通过降低实现的复杂度,这就更有可能出现多个正确的实现。
- '.'和'->'之间的区别。这种区别其实很没有必要。'.'运算符完全可以起到'->'所起的指针解引用的作用。
D 适合于?
- 经常使用 lint 或者类似的代码分析工具以期在编译之前减少 bug 的程序员。
- 将编译器的警告级别调到最高的人和那些告诉编译器把警告作为错误的人。
- 不得不依靠编程风格规范来避免常见的 C bug 的编程部门经理们。
- 认定 C++ 面向对象编程所允诺的功能由于 C++ 太复杂而不能达到的人。
- 沉溺于 C++ 强大的表达力但是被显式内存管理和查找指针 bug 折磨得精疲力尽的人。
- 需要内建的测试和验证机制的项目。
- 开发百万行规模的程序的团队。
- 认为语言应当提供足够的特征以避免显式处理指针的程序员。
- 编写数值运算程序的程序员。D 拥有众多直接支持数值计算的特征,例如直接提供了复数类型和拥有确定行为的 NaN
和无穷大。(这些都被加进了最新的 C99 标准,但是没有加进 C++ 中。)
- D 的词法分析程序和解析程序完全互相独立,并且独立于语义分析程序。这意味着易于编写简单的工具来很好地处理 D
源码而不用编写一个完整的编译器。这还意味着源码可以以记号的形式传递个某个需要它的程序。
D 不适合于?
- 现实一点说,没人会把上百万行的 C 或 C++ 程序用 D 重新写一遍,因为 D 不直接兼容 C/C++ 源代码,D
并不适合于遗留程序。(但是,D 对遗留的 C API 提供了很好的支持。)
- 非常小的程序――脚本或解释性语言如
Python、DMDScript<http://www.digitalmars.com/dscript/index.html>或者 Perl
更适合于这种情况。
- 作为第一门程序设计语言―― Basic 或者 Java 更适合于初学者。对于中级到高级的程序员来说,D 是他们优秀的第二门语言。
- 语言纯粹主义者。D 是一门实用的语言,它的每个特征都是为这个目的服务的,D 并没有想成为一门"完美"的语言。例如,D
拥有可以基本上避免在日常任务中使用指针的结构和语义。但是 D 仍然支持指针,因为有时我们需要打破这条规则。类似地,D
保留了类型转换,因为有时我们需要重写类型系统。