QR code

The End of Type Annotations

  • Translated by to

类型注释是使像Java这样的静态类型面向对象语言运行更快更安全的关键。没有注释,每个变量都会有效地坍缩为Object,强制运行时转换。代码会运行,但速度会更慢,同时会有更多的运行时错误。有些类型注释可以由程序员明确指定,而有些可以被推断出来。在Java中,举个例子,有一些难以解决的挑战阻止我们推断所有对象的类型。这并不是面向对象编程本身的基本限制,而是Java和类似语言中设计权衡的结果。在一个完美的面向对象语言中,所有变量类型都应该是可推断的。

想象一个简单的Java方法:

两个原因证明了使用BookCityPriceDelivery类型注释的必要性:编译器和程序员需要帮助。

首先,我们帮助编译器消除一些动态分派,转而使用静态调用。如果Book是一个类,而不是一个接口,book.price()调用可能被编译成跳转到绝对地址。没有关于book类的信息,.price()首先会进入虚拟表,找到地址,然后跳转。第二种情况更昂贵。附加到book的类型注解有助于避免这种情况。

其次,我们帮助自己编写安全的代码,避免“方法未找到”的运行时错误。如果book没有注释为Book,我们可能会错误地传递Integer,这意味着数据库中的书籍ID。在编译时,这不会导致错误。然后,在运行时,当在Integer类的虚拟表中找不到.price()时,我们会收到错误。

然而,编译器和程序员都可以改进。

有时,编译器可以推断变量的类型,而无需显式注释。例如,这段代码在Java中可以编译,从版本10开始。

较早版本的Java中使用的类型注解已被var关键字取代。

在这样一个小代码片段中,编译器可以推断类型。然而,对于bookcity参数可能会有所不足。通常情况下,对于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中被引入的原因。

在上面的代码中,变量名是名词。在编写良好的代码中,名词作为名称足以消除变量的歧义。不需要将其称为cityOfDeliverybookToDeliver。只需bookcity就足够了。

我们还根据它们的类型对变量进行命名:一个bookBook类型的,依此类推。通过查看变量的名称,我们可以知道它的类型。Book类型注解看起来像是一种语法上的冗余。它只会使代码更长,从而降低了代码的可读性。有理由期待类型推断能够解放我们的程序,摆脱这种冗余。

因此,更好的类型推断意味着代码的可读性更好。

像Haskell和ML系列这样的语言证明了完全类型推断是可行的。然而,它们仍然需要注释来处理边缘情况。Rust采取了一个中庸之道。它推断本地变量类型,但在公共接口处强制使用显式注释。直到最近,Go避免了泛型、运算符重载和大量反射,使推断变得简单。然而,它强迫程序员注释所有公共边界—函数签名、结构字段和接口。

我建议向前迈出一步,设计一种不需要任何类型注释的语言。这样的语言不应该有泛型、方法重载、反射以及任何其他阻碍100%类型推断的东西。然后,我们必须为这种语言设计一个编译器,用于编译整个程序,而不是单个文件。

这种语言可能是如此严格:如果变量的类型无法推断,编译将失败。

在这种语言中,书籍价格片段会是这样:

对我来说,这似乎比用Java编写的原始代码更易读。

尽管编译时间仍然存在限制。我们将这个问题转化为一个机会。程序员受到编译器的时间限制,被迫编写更小的模块。当他们需要更大的程序时,他们将其分解成通过IPC进行通信的模块,而不是保持在一个庞大的二进制文件中。

我们正在EOLANG中尝试这种方法,这是一种旨在通过消除使其不可判定的特性来最大化推断的语言。

Translated by ChatGPT gpt-3.5-turbo/42 on 2025-08-17 at 15:51

sixnines availability badge  GitHub stars