类型注释是使像Java这样的静态类型面向对象语言运行更快更安全的关键。没有注释,每个变量都会有效地坍缩为Object
,强制运行时转换。代码会运行,但速度会更慢,同时会有更多的运行时错误。有些类型注释可以由程序员明确指定,而有些可以被推断出来。在Java中,举个例子,有一些难以解决的挑战阻止我们推断所有对象的类型。这并不是面向对象编程本身的基本限制,而是Java和类似语言中设计权衡的结果。在一个完美的面向对象语言中,所有变量类型都应该是可推断的。
想象一个简单的Java方法:
两个原因证明了使用Book
,City
,Price
和Delivery
类型注释的必要性:编译器和程序员需要帮助。
首先,我们帮助编译器消除一些动态分派,转而使用静态调用。如果Book
是一个类,而不是一个接口,book.price()
调用可能被编译成跳转到绝对地址。没有关于book
类的信息,.price()
首先会进入虚拟表,找到地址,然后跳转。第二种情况更昂贵。附加到book
的类型注解有助于避免这种情况。
其次,我们帮助自己编写安全的代码,避免“方法未找到”的运行时错误。如果book
没有注释为Book
,我们可能会错误地传递Integer
,这意味着数据库中的书籍ID。在编译时,这不会导致错误。然后,在运行时,当在Integer
类的虚拟表中找不到.price()
时,我们会收到错误。
然而,编译器和程序员都可以改进。
有时,编译器可以推断变量的类型,而无需显式注释。例如,这段代码在Java中可以编译,从版本10开始。
较早版本的Java中使用的类型注解已被var
关键字取代。
在这样一个小代码片段中,编译器可以推断类型。然而,对于book
和city
参数可能会有所不足。通常情况下,对于Java程序来说,类型推断是不可判定的。由于泛型、方法重载、反射等复杂性。
复杂性是技术障碍。编译器无法推断所有变量的类型,因为分析整个程序将会过于昂贵。相反,它逐个文件进行编译。即使编译器获得了整个程序,Java在一般情况下仍会遇到不可判定性。逐个文件编译使得这一限制更为严格。
其他所有障碍,如泛型,编译器都无法克服:
无论编译器多么努力,在一般情况下,这个问题都没有答案。
我们程序员可以帮助编译器推断类型。
例如,我们可以停止使用泛型。我们可以有一个Library
,而不是List<Book>
,也可以有一个PhoneBook
,而不是Map<User, Phone>
。从Library
获取的对象的类型比从泛型List
获取的对象更容易推断。
我们还可以停止使用方法重载。我们可以创建printString(x)
和printInteger(x)
,而不是print(String x)
和print(Integer x)
。在更专门的方法中,参数的类型更容易推断。
我们还可以停止使用反射。
Java程序员可能还没有准备好做出如此激进的改变。然而,如果他们愿意这样做,不仅可以帮助编译器,也可以帮助自己。消除类型注解可以使代码更简洁,因此更清晰。这就是为什么var
语法在Java 10中被引入的原因。
在上面的代码中,变量名是名词。在编写良好的代码中,名词作为名称足以消除变量的歧义。不需要将其称为cityOfDelivery
或bookToDeliver
。只需book
和city
就足够了。
我们还根据它们的类型对变量进行命名:一个book
是Book
类型的,依此类推。通过查看变量的名称,我们可以知道它的类型。Book
类型注解看起来像是一种语法上的冗余。它只会使代码更长,从而降低了代码的可读性。有理由期待类型推断能够解放我们的程序,摆脱这种冗余。
因此,更好的类型推断意味着代码的可读性更好。
像Haskell和ML系列这样的语言证明了完全类型推断是可行的。然而,它们仍然需要注释来处理边缘情况。Rust采取了一个中庸之道。它推断本地变量类型,但在公共接口处强制使用显式注释。直到最近,Go避免了泛型、运算符重载和大量反射,使推断变得简单。然而,它强迫程序员注释所有公共边界—函数签名、结构字段和接口。
我建议向前迈出一步,设计一种不需要任何类型注释的语言。这样的语言不应该有泛型、方法重载、反射以及任何其他阻碍100%类型推断的东西。然后,我们必须为这种语言设计一个编译器,用于编译整个程序,而不是单个文件。
这种语言可能是如此严格:如果变量的类型无法推断,编译将失败。
在这种语言中,书籍价格片段会是这样:
对我来说,这似乎比用Java编写的原始代码更易读。
尽管编译时间仍然存在限制。我们将这个问题转化为一个机会。程序员受到编译器的时间限制,被迫编写更小的模块。当他们需要更大的程序时,他们将其分解成通过IPC进行通信的模块,而不是保持在一个庞大的二进制文件中。
我们正在EOLANG中尝试这种方法,这是一种旨在通过消除使其不可判定的特性来最大化推断的语言。
Translated by ChatGPT gpt-3.5-turbo/42 on 2025-08-17 at 15:51