译者 | 张健欣
策划 | 凌敏
James Gosling,通常被称为“Java 博士”,是一名加拿大计算机科学家,以 Java 编程语言之父闻名。他完成了 Java 的最初设计,实现了 Java 最初的编译器和虚拟机。日前,Evrone 的 DevRel、Grigory Petrov 对 James Gosling 进行了采访。InfoQ 对访谈内容进行了翻译,以飨读者。
James:我想我不会放弃类的。事实上,我发现类对于创作很有效。C 语言中有宏,这几乎是一场灾难,因为宏不是语言的一部分,它们是语言之外的东西。Rust 设计师尝试在语言中很好地适配宏。
其它语言,例如 Lisp 家族的所有语言,设法更优雅地适配宏,但它们有一种定义语法的方法,其中语法完全没有语义。在大多数语言中,语法和语义是紧密相连的。作为一个在过去写了很多 Lisp 代码的人,我对使用 Lisp 程序来操纵 Lisp 程序的技术非常着迷。这是我非常非常想念的一点。有些语言允许你用不同的方式来实现这一点,例如在 Groovy 中,你可以直接使用 AST,而 Rust 则有一些语法集成的宏。但我总觉得这里有一个有意思的研究问题:你能做得更多吗?
我能体会到 Lisp 对代码片段进行计算来生成新代码的感觉吗?在 Java 世界里,人们就是这样做的。这是一个更受欢迎的功能,尽管它的层级很低。因为人们将注解和可以使用某些不同语言生成字节码结合使用,这是超级强大的。它会在你意想不到的地方使用,例如 Jackson,并通过计算序列化程序获得了很多性能。
一方面,这是一种非常强大的技术。另一方面,它非常难用。事实证明它是可行的,但你能走多远?它们可能是有限制的。所以,你可以看看像 Lombok 这样的东西,它添加了一系列非常好的 Java 特性,但另一方面,它也显示出了弱点,因为这是一组应该内置的功能。而 Java Community Process 丧失了部分本应该有的 区性。我已经不在 区好几年了,但到处都有一些你可以做的事情。
James:像计算代码片段这样的特性,在 Java 中很难用的原因是,Java 试图做编译到机器代码的所有过程,而 Ruby 总是被解释执行的。当你这样做,但你不想尽你可能获得所有的性能时,事情就会变得很容易。但是如果你想同时获得强大的功能和终极性能,事情就会变得困难得多。
James:这几乎完全取决于开发者 区的规模,每一次破坏性的更新都会给开发者 区带来痛苦。如果你没有太多开发者,那么破坏性更新并不是一个大问题,但你必须考虑成本效益的平衡。如果你做了一个破坏性更新,它会增加一些痛苦,但也会带来一些好处。如果你将下标运算符从方括 改为圆括 ,则它可能完全不会为你带来任何好处,而是会带来巨大的痛苦。因为这是一个愚蠢的主意。
在 JDK 9 中,存在一个变化,这是引入的为数不多的破坏性更新之一,它造成的破坏是:如果你使用一些隐藏的 API,封装机制就会混乱,那些打破封装边界,并以不正确的方式使用工具的人,从 8 迁移到 9 就会很痛苦。但一旦我们克服这些,平台就有了更多创新自由。在 8 到 9 转换的特殊情况下,这意味着可以对平台进行分割,你实际上可以进行定制打包,从而使 Java 运行时环境更小。
另一个经常让人感到不适的地方是:如果某个功能存在 bug,人们为这个 bug 采取了变通方法,如果你修复了 bug,你可能会打破这些变通方法。在 Java 世界中,确实有过这样的例子,我们要么决定不修复 bug,要么引入一种正确的方法,这甚至体现在硬件上。sin 和 cos 有一个问题,它们有些错误的地方,因此你必须有正确和错误的指导说明。
James:嗯,两者都有。我非常喜欢使用静态类型系统的语言,因为它们为静态类型检查器和 IDE 提供了一个框架。我一生的大部分时间都是作为一名软件工程师度过的,对我来说,最不满意的消磨时间的方式就是寻找那些在奇怪时间点发生的模糊 bug。在 bug 浪费我的时间之前,我能做的任何能够使 bug 消失的事情都是极好的。所以,我非常喜欢 IDE 可以做的任何能够减少 bug 可能性的事情。因此,当我们研究动态类型语言(如 Java 和 Python)时,它们的推理框架比较少,因为它们不一定知道任何东西的类型,它们只是猜测而已。强类型语言(如 Java)为类型检查器提供了更严格的框架。在另一个层次上,有些东西可以进行全自动的定理证明。所以像 Dafny 这样的系统,它有一个非常复杂的定理证明器。因此,如果你想构建一个加密算法,你将能够从数学上证明属性。对于某些代码来说,这确实非常有用。
而且这在很大程度上取决于你的目的到底是什么。如果你是一名大学生,你正在努力完成作业,或者你是一名博士生,你正在努力毕业,那么当你写程序时,你的目标是它工作一次就行了,至少一次。因为你必须做一个演示,能够展示它,看看它是否有效。如果你在一个工业环境中,就像我大部分生涯所在的环境一样,那么它需要每次都能工作。一次工作和每次工作的区别是巨大的。因此,如果它只需要工作一次,那么更具动态性的语言就可以相当好地工作。如果你必须确保它能一次又一次地工作,那么所有的静态类型工具能够帮助你建立信心。但是如果你正在做的事情是,比如你是一名物理学家,你想算出一些计算的结果,它只需要运行一次。这取决于你所工作的背景。你所需要的软件可靠性越高,静态类型语言就越有帮助。
James:我对此没有什么想法,你在问一个关于未来的问题。“今天是黄金时代吗”,这个问题暗示:“它从今天走下坡路吗?”如果今天是黄金时代,那么明天就不会是黄金时代了。我认为,我们正在走向黄金时代,无论黄金时代是什么。我认为有很多有趣的改进可以发生。目前,我们有各种各样安全方面的危机,比如应该如何应对 络恐怖主义等。当这种事情发生时,我不认为现在是黄金时代。如果有某种方式,人们通过 区合作可以让 络恐怖主义终结——那将是黄金时代。我们拭目以待。总的来说,这确实是一个伟大的时代,但它可以变得更好。
James:要想真正获得性能提升,使用静态类型语言会有很大帮助。对于动态类型语言,比如 Python,这样的性能提升非常困难。通常,人们要做的就是在语言中添加注解,这样就可以得到 Type 这样的语言,它本质上是带有类型注解的 Java。这真的很有趣,因为 Java 本质上是 Java 删除了类型声明。因此,Type 本质上是具有置换语法的 Java。它们有 Pascal 风格的声明。但是,如果你只是用 Python 快速编写脚本,那么很多人都会觉得声明很烦人,因为考虑它们的变量类型是很烦人的。
在 Python 和许多其它语言中,通常只有一种数字,那就是双精度浮点数。不存在真正的整数,不存在字节和 16 位整数等概念上增加复杂性的东西,但这些复杂概念能提高性能。如果你有一个双精度浮点数和一个单精度浮点数,就会存在一个认知负担。要想做出明智的权衡,你必须了解一些数值分析。软件工程师普遍对数值分析一无所知,所以他们宁愿不去想它。如果你是一位使用 Python 的物理学家,你可能总是想要获取所有精度。当然,除非你需要在内存中放入一个非常大的数组,其中单精度和双精度或一个 8 位整数之间的差异才会非常重要。
在我有生之年,我修了太多数值分析课程,被劣质的数值分析搞崩溃的次数太多了,因此我很在乎精度。这取决于你在这个领域的位置,而脚本语言世界中的大多数人并不关心这类问题,他们的关注点是完全不同的。而且很多人实际上并不关心性能和数字的细节,他们关心的是:“速度够快吗”?性能有点儿像布尔值:速度够快,还是不够快。对于一些人来说,这更像是调整赛车。如果你能让一辆车每小时多跑两三英里,那么你更有可能赢得比赛。
James:这很大程度上取决于你的任务在程序空间中的位置。如果你想要完成的事情实际上是由 络和数据库以及其它所有东西所主导,如果你一直在做 RPCs,那么你应该做的第一件事是质疑这些 RPCs 是否都有价值。当人们谈论微服务时,它们是一件好事,但要明白它们至少比方法调用慢一百万倍。仔细想想这其中的含义。对于很多人来说,所有的低级细节都很重要。如果你知道高并发很重要,能够同时驱动数千个进程,进行主要的计算,如果你正在做数据库本身或一个主要的存储服务,那么你真的要非常关心。因此,这完全取决于手头的任务。
James:这类问题的上下文很重要。协程非常好,它们从 60 年代就开始被采用了。最早采用协程的语言是 Simula 67。Simula 是一种可爱的语言。我仍然怀念它。它没有线程,有协程,但它们执行协程的方式看起来很像线程。协程在真正的并行中神奇地避开了一些问题。对我来说,协程的一个问题是它们实际上不允许让你利用多个处理器,这就是我很长时间没有采用协程的原因。采用协程,你不能做真正的并行。
因此,人们看向具有真正并行的语言(比如 Erlang 和 Java)中的东西。你必须做的事情增加了另一层复杂性。通常情况下,处理这种复杂性的方法是非常仔细地策划原语。在 Java 中,你可以用 ConcurrentHashMap 做的事情非常神奇。一旦你使用了一种基于协程的语言,并且你试图利用多个处理器,如果你做了大量协程操作,而你并没有足够的处理器,那么你只会使一个处理器饱和。你真的很想使用多个处理器,因为世界上已经没有单核处理器了,对吧?每样东西都有很多内核,如果你真的想在一个问题上同时使用你所有的计算机处理器,你只需要克服和处理真正多线程所固有的复杂性。
然后是风格问题。想象你可以说“await 这”和“await 那”的环境,它们做了这个透明的控制反转,你只能被动屈服。虽然能使你的语法看起来非常像真正的线程。但这意味着,在真正的线程中,有许多棘手的问题需要避免。所以,如果你说“a = a + 1”,你知道这是在运算的中间,你不会被打断,所以你不必做同步。但还有一些其它地方,它不再采用这种风格,而是变成了一种事件导向的风格,你做你自己的事情,然后你把一个事件处理器插入到某个东西中来处理事情完成后发生的事情。这往往是 Java 的主要风格。这很好用,但可能有点笨重。
当我在 70 年代初发现 Simula 时,它有一种自然的风格。你只需要编程,你可以把你的计算看做是独立的东西,而其他事物是否与之交织对你来说是透明的。我发现,作为一种概念模型,它比事件编程要干净地多。它很难在幕后实现,但通常更容易思考。
James:我显然会有偏见。很长一段时间,Java 一直成功地作为软件开发新手的第一语言。但我学的第一种编程语言是 PDP-8 汇编代码,大致与 Fortran 并行使用。你可以教人们任何东西。其中一些语言比其它语言更容易理解,但这很大程度上取决于一个人最终的职业道路。如果你想成为一名全面的软件开发人员,构建大型的高性能的系统,那么其它语言很难打败在 JVM 上运行的语言。实际上,我不在乎你在 JVM 上使用哪种语言。我的意思是,Scala 和 Kotlin 都很好。Clojure 真的很有趣,但你必须用不同的方式思考。如果你是一名物理系学生,Python 就可以了。
我认为你选择哪一种语言并没什么大不了的。虽然很多人坚持他们所学的第一语言,并从事相关的工作,但如果你能让人们学习多种语言并反复切换是更好的。我认为,每个大学都应该为学生开设的一门课程是编程语言比较课程。在这学期里,你有五个不同编程语言的作业,让学生们能够习惯快速学习它们,并思考哪一种编程语言更好。很久以前,我参加了其中一门课程,每次作业我都用了最糟糕的语言,用 COBOL 进行数值计算。那只是娱乐!甚至我还用 Fortran 进行符 操作。令人惊讶的是,我仍得了个 A。
James:首先,我认为编程语言中的术语“模式匹配”有点误导。因为当我听到“模式匹配”这个短语,我想到的是正则表达式,无论是字符串上的正则表达式,还是树上的正则表达式。也许模式与树的形状匹配,随便什么。但是回到 Simula。Simula 有一个 inspect 语句,这个 inspect 语句几乎完全与许多模式匹配语句相同。也就是说,inspect 语句是一个 case 语句,其中 case 标签是类型名,你可以说:
Inspect P When Image doShow; When Vector doDraw;
你可以将其视为一个 case 语句,基于类型的 cases。大多数模式匹配语言提案都是这种类似的东西。就我个人而言,我很怀念这一点,我真的很喜欢。特别是如果发生的事情有点像 C 语言中的隐式转换,如果你说“inspect P When Image P do P”,那么 case 语句中的 P 现在就是 switch 标签的类型。在一种类似 C 的语法的语言中,你总是以强制转换结束。它看起来像:“如果 a 是 x 的实例,否则如果 a 是 y 的实例,那么……”Simula 中的“inspect”语句非常漂亮,我喜欢它,而这些模式匹配提案和语言特性中许多都是这样的。你可以称它为“类型实例(type case)”,但是如果你称它为“模式匹配”,并且它的功能比正则表达式小,那么它就会让人产生误解,有点像虚假广告。但是,作为一种功能,我认为它很棒。
James:这取决于你想要做什么。Java 虚拟机的一个特点是它内置了许多安全性和可靠性的概念。它们主要与内存模型的完整性有关,所以你不能构造一个指针。像 C 这样的语言,如果你没有构造指针的能力,你就不能实现 C。有些虚拟机没有严格的安全模型。如果你有一个安全的虚拟机,有些地方你就无法实现。但是有些人已经建立了不严格安全的虚拟机,没有内存分配模型。如果您想在 C 和 Kotlin 之间实现互操作性,您必须放弃一些安全性和可靠性。
原文链接:
https://evrone.com/james-gosling-interview
你有火狐,我有“水狐”:专为打脸Mozilla而生的Firefox分支 GitHub换帅:那位曾努力维持代码托管平台中立性的CEO要离职了
微软产品经理:你不能不知道的6个Web开发者工具 程序员薪资倒挂严重,只能跳槽换高薪,IT公司为什么不愿加钱留住老员工?
活动推荐
InfoQ 引航计划正式启动,下一个引导技术领域共建发展的 Pioneer 就是你!
扫描下方二维码获取更多活动信息!
点个在看少个 bug??
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!