Back
Featured image of post Kotlin - 面向 IDE 的编程语言

Kotlin - 面向 IDE 的编程语言

本文是翻译文章,主要吹了一下 Kotlin,踩了一下 Python。

本文是对发布在 Medium 上的文章 Kotlin — IDE-Oriented Programming 的翻译,部分图因为不太清晰,所以是我新配的。有些外链(如维基百科)如果有对应的中文版本,我替换了它们。

请注意,虽然本翻译按照 CC BY-SA 4.0 分发,但没有原作者的授权,我本质上不享有翻译权。所以如果想转载本文,你首先应该取得原作者的同意。

根据编程语言的特性,人们将他们分类为某些范式。最著名的争辩是在一个语言是「面向对象」、「面向过程」抑或「函数式」之间的。

在生产中似乎和学术有些不同,包括一些可能是玩笑的说法:

  • 炒作型开发 - 毫无根据地使用某种被炒作的技术,例如区块链、NoSQL、微服务。另请参见货物崇拜编程
  • 巫毒编程 - 在源码中乱戳,直到如预期执行;这是 PHP 程序员的惯用范式。
  • 基于 Excel 的编程 - 关键业务逻辑保存在没有版本控制而且容易被篡改的 Excel 工作表中

今天我想提出一个我注意到的新范式,并讨论 Kotlin 如何有意或非有意地将该范式良好实现。

IDE 驱动的开发

我已经在《希望计算机科学学位教会了我编程》中赞美了 IDE 的优点。「开发人员在文本编辑器中编写了一个应用程序,保存它,退出编辑器,运行编译器,在一张纸上写下错误信息,然后追溯错误信息。」和那时相比,如今编程的方式已经大为不同。1991 年的 Microsoft Visual Basic 被认为是一个真正的 IDE,但我认为早期的 Java IDE(Eclipse 2001、IntelliJ 2001、NetBeans 1997)对我们今天的开发方式产生了最为深远的影响。

正如这篇文章所说:

老掉牙的笑话:如果你建造的东西连白痴都能用,那么只有白痴才会用。IDE 让人们从查阅厚如电话簿的参考书中脱离。并将大量工作减少到只需要单击几下。这使得编程更容易,抑或让糟糕的代码遍地都是?「两个都有」,退伍军人回答道。

Java 在 90 年代后期风靡全球。Java 提出了面向对象编程,它设想将一个复杂程序分成模块化的封装类,这些类可以轻易替换。管理者们开始以同样的方式看待开发人员,因为可以与大型 Java 开发人员池中的任何人互换。

IDE 让 Java 开发者从列表(包含所有与输入匹配的方法)中选择自动补全来编程。IDE 也会自动处理构建系统,导包,并且格式化代码,检查你参数的类型。即使是菜鸟程序员也可以在程序上戳戳戳,直到 IDE 满意为止(另一种形式的巫毒编程)。每当我看到一篇高级程序员不能在面试中解决 XXX 时,我都会责怪 IDE。

来自俄罗斯的爱

Kotlin 登场了。那是 2020 年的 4 月,我第一次失业的时候,听说了 Kotlin。它不断地出现在 StackOverflow 的广告中,其中很多是我想去的公司。因此,我在 Android Studio 中使用 Kotlin 制作了一个小型演示应用(后来变成了 Mundraub Navigator,一个下载量超过 5 万的真实应用程序)。Kotlin 解决了 Java 的许多问题,例如冗余的代码风格、缺乏空安全、装箱类型、受检异常。还添加了字符串模板、操作符重载、范围表达式。

Kotlin 的开发者主要来自位于圣彼得堡的 JetBrains ——同时也是世界上最好且最常用 IDE 的制造者:

JetBrains 的 IDE

它们中的大多数都是用 Java 实现的,而 Kotlin 的出现是为了在他们自己的开发过程中提高生产力(我的意思是,他们可能已经在使用 IntelliJ 来开发 IntelliJ),同时保持与现有 Java 代码库的完全兼容性。

总之,JetBrains ——无论好坏——创造了一种只有在他们自己的 IDE 上才有意义的语言。让我娓娓道来。

基于点的编程

比较等价的 Kotlin 和 Python 代码:

Kotlin

solution.sortedBy { it.second }.map { it.first }.toString()

Python

str([x[0] for x in sorted(solution, key=lambda x: x[1])])

你会注意到 Kotlin 定义了链式函数,而 Python 有全局的内置方法。例如 a.sorted()sorted(a)a.toString()str(a)。最终 Kotlin 形成一长串调用 a.map {...}.sorted().toString,而 Python 不断嵌套 str(sorted(map(...)))

这有什么好处?只需要在表达式末尾添加一个点,IDE 的选择列表就会激活,并且帮你找到想要的内容。而在 Python 中,你需要「提前」知道所有函数名,并且要将所有圆括号、方括号、大括号一一匹配。

拓展函数

Kotlin 也允许你定义拓展函数。拓展函数不真正地添加到对象里,只有你自己的代码能够使用他们。(译者注:本质上拓展函数就是帮你把 a.doSomething(b) 转换成 doSomething(a, b))所以工具方法也可以使用基于点的代码风格:

fun <T> List<T>.toPair(): Pair<T, T> {
    if (this.size != 2)
        throw IllegalArgumentException("List is not of length 2!")
    return Pair(this[0], this[1])
}
val myList = listOf(7, 9)
val myPair = myList.toPair()

我在 kohttp 库中还看见过更有创造性的用例,HTTP GET 请求是 String 类型的拓展函数:

"http://whatthecommit.com/index.txt".httpGet()

更多点

你也可以像这样书写中缀表达式。下面的代码是合法的 Kotlin,计算 \((3-5) \times 2 = -4\)(不要真的这么写):

3.minus(5).times(2)

我自己也喜欢用点风格的 for 循环:

cardInfos.forEach { it.submitted = true }

for (cardInfo in cardInfos) 
    cardInfo.submitted = true

类型和名称提示

IDE 添加了关于变量/参数的类型和名称信息,让 Kotlin 代码在 IDE 里更加可读(而不是在 GitHub 或 Kotlin Playground 里)。

IDE 的类型和名称提示

Android Studio 显示 getFromLocation 的第三个参数名为 maxResults,这比单纯的 1 提供。还可以看到,在第 6 行传递给块的参数具有默认参数 it 及其类型 Address。你也可以将鼠标悬浮在上面,以获取更多信息。

Python 有类似的机制(包括非常酷的特性,即任何函数参数都可以使用其名称作为关键字来调用),但这需要开发人员每次都显式添加它们(他们可能不会这样做);编辑器不会给你任何提示。 例如,可以通过添加注释来改进这个愚蠢的小辅助函数:

def concat_lists(a):
    return sum(a, [])

def concat_lists(a: list[list]):
    return sum(a, start=[])

结论

Java 迎接了千篇一律的商业应用编程时代,并且非常适合静态分析(和 C++ 相比他的功能更加简单),使得行业从基于终端的文本编辑器转向(太)易于使用的图形 IDE。

Kotlin 被设计成能和 IDE 良好结合,这使得 IDE 成为了语言的一部分。这带来了非常优秀的特性,但同时,我们离开不了 IDE。

感谢 Kotlin,我不再需要在强大的语言(Python)和强大的 IDE 支持(Java)之间抉择。

comments powered by Disqus