Perl的七大致命缺陷

在Perl 4时代,我列出了Perl中最常见的‘陷阱’。其中大部分都在Perl的当前版本中得到了修复,有些让我感到非常惊讶。本着同样的精神,这里是我目前列出的Perl中‘不尽人意’之处,从一个相对严肃的编程语言设计角度来说。我相信这些都是真正的陷阱,并不总是显而易见。其中一些可以通过编程的严谨性来解决;一些据说已经在Larry的5.002版本中修复了;但还有一些是固有的设计决策,可能需要破坏语言本身才能解决,就像csh的设计缺陷无法解决一样。

当然,对于许多类型的应用程序,Perl也有很多优点,使其不仅是一个合理的,而且往往是今天市场上最佳的选择。我只是在提供一种视角;将其视为Perltrap pod页面的最终更新。

1. 隐式行为和隐藏的上下文依赖

函数重载仅在返回类型上而不是参数类型上,这总是隐式的,而语言无法推断。这对于每天都要编写Perl代码的人来说,常常是一个令人震惊和可怕的惊喜。类型转换(非引用类型)是沉默而致命的,尤其是在聚合和标量之间。这对许多人来说很难预测。各种函数存在一些不明显的默认行为,而且无法关闭,这太令人惊讶了,并且非常危险。

2. 加括号或不加括号?

添加或不添加括号可能会产生语义变化,而不是仅仅分组,这一点很难理解。有时你做或不做都会受到惩罚。通过在几乎所有情况下允许但不要求括号,人们会困惑是否应该使用它们,并且当它们的使用或不用会极大地改变程序的行为时,会感到非常不安。这在试图找出如何使正则表达式返回它们匹配的内容时尤其令人烦恼。

3. 全局变量

没有强制执行声明或检测完全全局变量的规定,这可能导致非常难以检测的程序错误。隐式使用 $\_ 是一个经典案例,导致函数在调用栈中神秘地失败。没有 use strict globals 或类似的命令来强制声明甚至可导出模块级别的全局变量。无法拥有词法作用域的预定义文件句柄或内置变量(如 $_$? 等),而动态作用域的版本对传统语言的程序员来说很困惑。

4. 引用与非引用

尽管在v5中引入引用是一个关键步骤,但由于与旧版v4代码保持向后兼容性,遗留代码和基本系统仍然使用太多的类型和随之而来的混淆。这意味着人们对 $@% 的区别仍然感到困惑。特别是,他们期望在数组或散列上工作的东西能够透明地作用于对同一对象的引用,反之亦然。这在人们试图处理复杂的数据结构时就会表现出来。

5. 没有原型

没有原型(函数签名)使得无法创建与内置函数完全相同的函数,同时也使得错误静态分析变得困难。即使为常规函数引入了原型,如何将其扩展到用户定义的对象类和方法?如何原型化返回值?

6. 没有编译器对I/O或正则表达式对象的支持

输入输出系统使用裸词不干净且不愉快,因为没有真正良好的编译器对I/O句柄的支持。需要彻底重写open()接口及其相关功能,最好是采用面向对象范式,但又不破坏旧代码。正则表达式系统也同样过时:由于没有真正的编译器对编译正则表达式的支持,要么性能极差,要么使用神秘的技巧来规避这个问题。

7. 随意异常模型

在库、模块或类中,没有标准模型或指南用于异常处理,这意味着你不知道应该捕捉什么异常,不应该捕捉什么异常。库是抛出异常还是只返回false?即使它抛出了异常,也没有标准的异常命名规范,因此很难知道如何捕捉所有数字异常、所有I/O异常等。人们错误地使用eval $str既用于代码生成也用于异常处理,这不仅推迟了错误到运行时,而且有很大几率会丢失这些错误。

标签

反馈

这篇文章有什么问题?请在GitHub上打开问题或pull request来帮助我们。