编程语言中的冗余

2020-05-03 04:19:16

消除冗余通常被视为提高生产效率和减少浪费的一种方式。但是,正确的冗余可以极大地提高质量。例如,中世纪发明的复式簿记是会计的一大进步,因为它引入了冗余,几乎消除了常见的算术错误。

良好的冗余通过具有通往相同结果的两个独立路径来检测故障。一条路径中的故障不会影响另一条路径,因此结果中的差异表明存在错误。

不良冗余的区别在于要么不提供可检查的结果,要么冗余路径相互依赖,使得一条路径中的错误传播到另一条路径,因此错误的结果是一致的。

编程语言广泛使用它来减少编码错误。如果一种语言完全没有冗余,那么任何随机的字符序列都是有效的程序。编译器生成的每条错误消息都是查找用户错误的语言中的冗余示例。几乎没有冗余的语言的一个例子是机器代码-几乎任何位模式都是有效的操作码。任何为机器代码编写过反汇编程序的人都知道这几乎是不可能的……。

变量声明就是其中之一。但是,由于编译器可以根据上下文计算出声明的需要,所以声明似乎是可以丢弃的主要冗余。这称为隐式变量声明。这听起来是个好主意,而且它经常被载入新的语言中。问题是,编译器无法区分预期的新声明和打字错误-维护不善的程序员也无法区分。不过,过了一段时间,那个..。

为什么需要分号?编译器完全有能力弄清楚这一点。但是,如果是这样的话呢:

这可以是(x=3+y*p++),其中*是乘法而不是间接的。缺少分号也会使错误恢复变得很差,因为编译器无法计算出当前错误语句的结束位置和下一个错误语句的开始位置。分号在文本中形成漂亮的“锚”,帮助编译器和阅读器与代码结构同步。

(JavaScript是一个示例,其中分号是可选的,并且是从语法中推断出来的。Python不是一个示例,因为它仍然使用像\n这样的词法提示来指示语句的结束。)。

编程语言中冗余的最佳示例可能是单元测试。单元测试是函数功能的另一种规范,但它们指定的不是方法,而是结果。在结果中重现的方法中出现相同错误的几率非常、非常低。这意味着即使只适度使用单元测试也可以显著提高程序质量,这就是D编程语言内置单元测试支持的原因。

冗余并不总是好的。例如,在C语言中,源代码分为头文件和实现文件。声明在这两个版本中都有转载。这种冗余的问题在于,副本是字面上复制的文本-其中一个中的错误被简单地复制到另一个中,没有赋予冗余任何价值。有用的冗余需要是独立的。

乍一看,这看起来是一个很好的冗余。它正在检查tmp的类型是否为int。但是不,它没有检查类型,它强制类型为int,并将初始化式(a+b)转换为int。如果a和b被重新声明为某个其他类型(如无符号或浮点型),这可能会导致问题。为了解决这个问题,D编程语言引入了auto,将tmp声明为(a+b)类型:

一种常见的情况是C++中声明和表达式之间的语法歧义。例如:

这是将P声明为指向T的指针,还是将T和P相乘?在这里,少量的冗余将会有很大的帮助。

在C++中,重载使用<;和>;来表示模板参数列表。什么功能:

刻薄?这种缺乏冗余性的后果是出了名的迟钝错误消息,因为编译器没有太多的信息来指导它猜测用户的意图。

C++添加了一些关键字,如typeName,以及一些产品,如->;template,以增加冗余,从而改进错误检查和诊断。

通过查看编译器实现者倾向于随着时间的推移添加的警告诊断,您可以感觉到语言中缺少冗余的地方。对于新语言的设计者来说,常见的警告是改进灵感的丰富来源。

许多编程语言设计者错误地认为消除冗余可以提高程序员的工作效率。这一点通过小的基准来展示,表明它们是多么简洁,暗示简洁使一种语言变得强大和富有表现力。这对于小程序确实很有效,比如只有几个脚本