Why Kotlin,为什么你应该选择Kotlin ?

为什么你应该选择Kotlin ?

编程语言设计是从满足机器需求到满足程序员需求的进化途径。

我们概述了编程语言的历史发展,以便您了解Kotlin适合的位置以及为什么要学习它。这个原子介绍了一些主题,如果您是新手,现在可能看起来太复杂了。在您阅读了更多本书之后,可以随时跳过此原子。

语言设计者发明了一种编程语言,并将其实现为解释器编译器,它们也是程序。实施者通常至少在最初是语言设计者。

早期的语言着重于硬件限制。随着计算机功能的增强,更新的语言将转向注重可靠性的更复杂的编程。这些语言也可以根据编程的心理来开始选择功能。

每种编程语言都是实验的集合。从历史上看,编程语言设计一直是关于使程序员提高生产率的一系列猜测和假设。这些实验中有些失败,有些成功,有些非常成功。

我们从每种新语言的实验中学习。一些语言解决的问题最终证明是偶然的,而不是根本的,或者环境发生了变化(更快的处理器,更便宜的内存,对编程和语言的新理解),并且该问题变得不那么重要,甚至变得无关紧要了。如果这些想法过时并且语言没有发展,它就会从使用中消失。

最初的程序员直接使用代表处理器机器指令的数字进行工作。这种方法产生了许多错误,并且创建了汇编语言,以助记符操作码替换数字(程序员可以更轻松地记住和阅读的单词以及许多其他有用的工具)。但是,汇编语言指令和机器指令之间仍然存在一对一的对应关系,程序员必须编写每一行汇编代码。此外,每个计算机处理器都使用其自己独特的汇编语言。

用汇编语言开发程序非常昂贵。高级语言通过提供远离低级汇编语言的抽象级别来帮助解决该问题。在这里,我们提供了所选语言的历史记录,以选择它们对跟随其后的语言的影响。所有这些语言最终都启发了Kotlin的设计,有时甚至成为做事的榜样。

FORTRAN:FORMULA TRANSATION(1957年)

为供科学家和工程师使用而设计,Fortran的目标是使对方程式的编码更容易。经过微调和测试的Fortran库今天仍在使用,但是通常将它们“包装”以使它们可以从其他语言中调用。

LISP:LISt处理器(1958)

LISP并非特定于应用程序,而是体现了基本的编程概念。它是计算机科学家的语言,也是第一门函数式编程语言(您将在本书中学习函数式编程)。其功能和灵活性之间的权衡是效率:LISP通常太昂贵,无法在早期机器上运行,并且直到最近几十年,机器才变得足够快以至于使LISP的使用重新流行。例如,GNU Emacs编辑器完全用LISP编写,并且可以使用LISP进行扩展。

ALGOL:算法语言(1958)

可以说这是1950年代最有影响力的语言,因为它引入的语法在许多后续语言中仍然存在。例如,C及其派生词是“类ALGOL”语言。

COBOL:COmmon商业导向语言(1959)

专为业务,财务和管理数据处理而设计。它具有类似英语的语法,并且旨在具有自我说明性和高度可读性。尽管此意图通常失败了-COBOL因错误放置期间引入的错误而著名-美国国防部强迫大型计算机广泛采用它,并且系统今天仍在运行(并且需要维护)。

BASIC:初学者的通用符号说明代码(1964)

这是使编程变得可访问的早期尝试之一。虽然非常成功,但是它的功能和语法受到限制,因此对于需要学习更复杂的语言的人来说,它只是部分有用。它主要是一种解释性语言,这意味着要运行它,您需要程序的原始代码。尽管如此,许多有用的程序还是用BASIC编写的,尤其是作为Microsoft“ Office”产品的脚本语言编写的。人们甚至将BASIC看作是第一种“开放”编程语言,因为人们对其进行了许多修改。

Simula 67,原始的面向对象语言(1967)

一个模拟通常涉及到很多“对象”相互交融。不同的对象具有不同的特征和行为。当时存在的语言在用于模拟时比较笨拙,因此开发了Simula(另一种“类似ALGOL的”语言)来为创建模拟对象提供直接支持。事实证明,这些思想对于通用编程也很有用,这就是面向对象(OO)语言的起源。

帕斯卡(1970)

Pascal通过限制语言来提高编译速度,因此可以将其实现为单遍编译器。这种语言迫使程序员以特定的方式来构造他们的代码,并在程序组织上施加了一些笨拙和难以理解的约束。随着处理器变得更快,内存更便宜,编译器技术更好,这些约束的影响变得太昂贵了。

Pascal的实现来自Borland的Turbo Pascal,最初在CP / M机器上工作,然后转移到早期的MS-DOS(Windows的前身),后来演变为Windows的Delphi语言。通过将所有内容存储在内存中,Turbo Pascal在功率非常低的机器上以闪电般的速度进行编译,从而极大地改善了编程体验。它的创建者Anders Hejlsberg后来继续设计C#和TypeScript。

Pascal的发明者Niklaus Wirth创建了后来的语言:Modula,Modula-2和Oberon。顾名思义,Modula致力于将程序分为模块,以更好地组织和更快地进行编译。大多数现代语言都支持单独的编译和某种形式的模块系统。

C(1972)

尽管高级语言的数量不断增加,但是程序员仍在编写汇编语言。这通常称为系统编程,因为它是在操作系统级别完成的,但是它还包括专用物理设备的嵌入式编程。这不仅艰巨而昂贵(Bruce开始了他的职业生涯,为嵌入式系统编写汇编语言),而且它不是可移植的-汇编语言只能在为其编写的处理器上运行。C被设计为一种“高级汇编语言”,它仍然足够接近您很少需要编写汇编语言的硬件。更重要的是,一个C程序可以在任何带有C编译器的处理器上运行。C将程序与处理器解耦,从而解决了一个巨大且昂贵的问题。结果,以前的汇编语言程序员在C语言中的生产力可能大大提高。C如此有效,以至于最近的语言(特别是Go和Rust)仍在尝试将其用于系统编程。

闲聊(1972)

从一开始就设计为纯粹面向对象,Smalltalk作为实验平台和演示快速应用程序开发的平台,极大地推动了面向对象和语言理论的发展。但是,它是在语言仍为专有时创建的,Smalltalk系统的入门价格可能高达数千美元。它是经过解释的,因此您需要一个Smalltalk环境来运行程序。直到编程世界发展之后,开源Smalltalk实现才出现。Smalltalk程序员为以后的OO语言(例如C ++和Java)受益匪浅。

C ++:带有对象的更好的C(1983)

Bjarne Stroustrup创建了C ++,因为他想要更好的C语言,并且希望支持他在使用Simula-67时经历的面向对象的构造。Bruce担任C ++标准委员会成员的头八年,并撰写了三本有关C ++的书,其中包括《 C ++ 思维》

与C的向后兼容性是C ++设计的基本原理,因此C代码几乎可以在C ++中进行编译,而无需更改。这提供了一条简单的迁移路径-程序员可以继续使用C进行编程,获得C ++的好处,并在仍保持生产力的同时缓慢地尝试C ++功能。对C ++的大多数批评都可以追溯到与C向后兼容的约束。

C的问题之一是内存管理问题。程序员必须首先获取内存,然后使用该内存运行操作,然后释放内存。忘记释放内存被称为内存泄漏,可能导致可用内存用尽并导致进程崩溃。C ++的初始版本在这方面进行了一些创新,并与构造函数一起确保适当的初始化。该语言的更高版本在内存管理方面进行了重大改进。

Python:友好而灵活(1990)

Python的设计师Guido Van Rossum基于“为所有人编程”的灵感创建了该语言。他对Python社区的培育使它在编程领域成为最友好和最支持的社区。Python是最早的开源语言之一,几乎可以在包括嵌入式系统和机器学习在内的每个平台上实现。它的动态性和易用性使其成为自动化小型重复性任务的理想选择,但其功能也支持大型复杂程序的创建。

Python是一种真正的“草根”语言;它从来没有一家公司来推广它,而其粉丝的态度从来都不是推销该语言,而只是帮助任何想要学习它的人。该语言不断稳步改进,近年来,其流行度猛增。

Python可能是第一个将功能和OO编程相结合的主流语言。它早于Java使用垃圾回收的自动内存管理(您通常不必自己分配或释放内存),并且能够在多个平台上运行程序。

Haskell:纯函数式编程(1990)

受专有语言Miranda(1985)的启发,Haskell被创建为纯函数式编程研究的开放标准,尽管它也已用于产品。Haskell的语法和思想影响了包括Kotlin在内的许多后续语言。

Java:虚拟机和垃圾收集(1995)

詹姆斯·高斯林(James Gosling)和他的团队的任务是为电视机顶盒编写代码。他们决定不喜欢C ++,而不是创建盒子,而是创建Java语言。Sun Microsystems公司为免费语言提供了巨大的市场推动力(当时还是一个新主意),试图控制新兴的互联网格局。

互联网支配时间的这种感知时间窗给Java语言设计带来了很大压力,从而导致了许多缺陷(《Thinking in Java》一书阐明了这些缺陷,因此读者准备好应对这些缺陷)。尽管Java取得了巨大的成功,但Kotlin的一个重要设计目标是修复Java的缺陷,使程序员可以提高工作效率。目前,Java的主要开发人员,Oracle的Brian Goetz,尽管继承了许多限制,但在Java方面做出了令人惊讶的惊人改进。

Java的成功来自两个创新功能:虚拟机垃圾回收。这些语言可用其他语言提供,例如LISP,Smalltalk和Python具有垃圾回收功能,而UCSD Pascal则在虚拟机上运行,但是对于主流语言却从未考虑过它们实用。Java改变了这一点,并且这样做使程序员的工作效率大大提高。

虚拟机是语言和硬件之间的中间层,因此该语言不必为特定处理器生成机器代码。它只需要生成一种在虚拟机上运行的中间语言即可。虚拟机需要处理能力,在Java之前,虚拟机被认为是不切实际的。在Java虚拟机(JVM)引起了Java的口号是“一次编写,到处运行”。另外,可以通过针对JVM轻松开发其他语言。例如,Groovy(一种类似于Java的脚本语言)和Clojure(一种LISP版本)。

垃圾回收解决了忘记释放内存的问题。有时很难知道何时不再使用某个存储。由于内存泄漏,项目已被严重延迟甚至取消。尽管垃圾回收是以某些先前的语言出现的,但是在Java证明它是可行的之前,垃圾回收被认为会产生不可接受的开销。

JavaScript:仅在名称中使用Java(1995)

原始的Web浏览器只是从Web服务器复制并显示页面。Web浏览器激增,成为需要语言支持的新编程平台。Java希望成为这种语言,但是对于这项工作来说太尴尬了。JavaScript从LiveScript开始,并内置于NetScape Navigator中,这是最早的Web浏览器之一。将其重命名为JavaScript是NetScape的营销策略,因为该语言与Java仅存在相似的相似性。

随着Web的兴起,JavaScript变得异常重要。但是,JavaScript的行为是如此难以预测,以至于道格拉斯·克罗克福德(Douglas Crockford)用嘲讽的标题JavaScript(Good Parts)写了一本书,在书中他演示了该语言的所有问题,以便程序员可以避免它们。ECMAScript委员会随后的改进彻底改变了JavaScript,以至于原始JavaScript程序员无法识别。现在,它被认为是稳定和成熟的语言。

规模:可缩放(2003)

马丁·奥德斯基(Martin Odersky)创建了Scala以在Java虚拟机上运行:扛在JVM上完成的工作,与Java程序进行交互,并可能想到它可能会取代Java。作为研究人员,Odersky和他的团队使用Scala作为实验语言功能的平台,特别是Java中未包含的功能。

这些实验具有启发性,其中许多发现通常以改进的形式进入科特林。例如,重新定义运算符(如+在特殊情况下使用)的功能称为运算符重载。它包含在C ++中,但不包含在Java中。Scala添加了运算符重载,但还允许您通过组合任何字符序列来发明新的运算符。这通常会产生混乱的代码。Kotlin包含有限形式的运算符重载,但是您只能重载已经存在的运算符。

Scala也是对象功能的混合体,例如Python,但重点是纯函数和严格对象。这有助于激发Kotlin成为对象功能混合动力的选择。

与Scala一样,Kotlin在JVM上运行,但与Scala的交互比Java容易得多。此外,Kotlin面向JavaScript(Android操作系统),并为其他平台生成本机代码。

原子Kotlin是从原子Scala中的思想和材料演变而来的。

为什么选择科特林?(2011年推出,版本1.0:2016)

正如C ++最初旨在成为“更好的C”一样,Kotlin最初也致力于成为“更好的Java”。此后,它已大大超越了目标。

Kotlin的设计理念使它与几乎所有前任产品区分开来,因为它明确避免发明新的语言功能来解决感知到的问题。取而代之的是,对这些功能进行了现场测试并证明其特别有价值之后,它从其他编程语言中选择了最成功,最有用的功能。

因此,如果您来自另一种语言,则可能会在Kotlin中识别该语言的某些功能。这是有意的:Kotlin通过利用经过测试的概念来最大化生产率。

这个原子并不假定您是程序员,这使得很难解释Kotlin相对于替代方案的大多数好处。但是,有两个主题非常有影响力,并且可以在此早期阶段进行解释:Java互操作性和指示“无价值”的问题。

毫不费力的Java互操作性

要成为“更好的C”,C ++必须与C的语法向后兼容,但是Kotlin不必与Java的语法向后兼容-它仅需要与JVM一起使用。这使Kotlin设计人员可以自由地创建更简洁,功能更强大的语法,而不会出现使Java混乱的视觉噪声和复杂性。

为了使Kotlin成为“更好的Java”,尝试它的体验必须愉快而顺畅,因此Kotlin可以轻松地与现有Java项目集成。您可以编写一小段Kotlin功能,并将其插入现有的Java代码中。Java代码甚至不知道Kotlin代码在那里,它看起来像是更多的Java代码。

公司通常会通过使用该语言构建独立程序来研究一种新语言。理想情况下,该程序是有益的,但不是必需的,因此,如果项目失败,则可以以最小的损失将其终止。并非每个公司都希望花费这种实验所需的资源。由于Kotlin无缝集成到现有的Java系统中(并从该系统的测试中受益),因此尝试Kotlin以确定它是否合适非常便宜甚至免费。

此外,创建Kotlin的公司JetBrains以“社区”(免费)版本提供IntelliJ IDEA,其中包括对Java和Kotlin的支持以及易于将二者集成的能力。它甚至有一个使用Java代码的工具,(大部分)将其重写为Kotlin。

附录B涵盖了Java互操作性。

代表空虚

Kotlin的一项特别有益的功能是它可以解决编程难题。

当有人递给您一本字典并要求您查找一个不存在的单词时,您会怎么做?您可以通过为未知单词定义定义来保证结果。一种更有用的方法是说:“该词没有定义。” 这表明了编程中的一个严重问题:对于未初始化的存储或操作结果,如何指示“无值”?

空引用由东尼·霍尔,谁后来将其称为在1965年发明了ALGOL“我的数十亿美元的错误。” 一个问题是,它太简单了-有时被告知房间空着是不够的。例如,您可能需要知道为什么它为空。这导致了第二个问题:实现。为了提高效率,它通常只是一个特殊的值,可以容纳少量的内存,还有什么比已经为该信息分配的内存更好的呢?

原始的C语言没有自动初始化存储,这引起了许多问题。C ++通过将新分配的存储设置为全零来改善这种情况。因此,如果未初始化数值,则它只是数字零。这看起来似乎还不错,但是它允许未初始化的值悄悄地溜走(新的C和C ++编译器经常警告您这些问题)。更糟糕的是,如果一块存储是一个指针(用于指示(指向)另一块存储),则空指针将指向内存中的零位置,这几乎肯定不是您想要的。

Java通过在程序运行时(即运行时)报告错误来防止访问未初始化的值。尽管这会发现未初始化的值,但是它不能解决问题,因为可以运行程序来验证程序不会崩溃的唯一方法。Java代码中有大量此类错误,程序员浪费大量时间来查找它们。

Kotlin通过防止在程序运行之前执行可能导致空错误的操作来解决此问题。这是Java程序员采用Kotlin时最著名的功能。这一功能可以最大程度地减少或消除Java的空错误。

丰富的福利

无论您是否是Java程序员,我们都能在这里解释的两个功能(不需要更多的编程知识)产生巨大的不同。如果Kotlin是您的第一语言,而您最终需要一个需要更多程序员的项目,那么将众多现有Java程序员之一招募到Kotlin会容易得多。

Kotlin还有许多其他好处,除非您对编程有所了解,否则我们将无法解释。这就是本书其余部分的目的。

语言通常是出于激情而不是出于理性而选择的……我正在努力使Kotlin成为一种因某种原因而被人们喜爱的语言。— Kotlin首席语言设计师Andrey Breslav。

Why Kotlin?

Programming language design is an evolutionary path from serving the needs of the machine to serving the needs of the programmer.

We give an overview of the historical development of programming languages so you can understand where Kotlin fits and why you might want to learn it. This atom introduces some topics which, if you are a novice, might seem too complicated right now. Feel free to skip this atom and come back to it after you’ve read more of the book.

A programming language is invented by a language designer and implemented as either an interpreter or a compiler, which are also programs. The implementer is usually the language designer, at least initially.

Early languages focused on hardware limitations. As computers become more powerful, newer languages shift toward more sophisticated programming with an emphasis on reliability. These languages can also begin choosing features based on the psychology of programming.

Every programming language is a collection of experiments. Historically, programming language design has been a succession of guesses and assumptions about what will make programmers more productive. Some of those experiments fail, some are mildly successful and some are very successful.

We learn from the experiments in each new language. Some languages address issues that turn out to be incidental rather than essential, or the environment changes (faster processors, cheaper memory, new understanding of programming and languages) and that issue becomes less important or even inconsequential. If those ideas become obsolete and the language doesn’t evolve, it fades from use.

The original programmers worked directly with numbers representing processor machine instructions. This approach produced numerous errors, and assembly language was created to replace the numbers with mnemonic opcodes—words that programmers could more easily remember and read, along with a number of other helpful tools. However, there was still a one-to-one correspondence between assembly-language instructions and machine instructions, and programmers had to write each line of assembly code. In addition, each computer processor used its own distinct assembly language.

Developing programs in assembly language is exceedingly expensive. Higher-level languages help solve that problem by providing a level of abstraction away from low-level assembly languages. Here we give a history of selected languages, chosen for their influence on those that followed them. All these languages ultimately inspired the design of Kotlin, sometimes by being an example of what not to do.

FORTRAN: FORmula TRANslation (1957)

Designed for use by scientists and engineers, Fortran’s goal was to make it easier to encode equations. Finely-tuned and tested Fortran libraries are still in use today, but they are typically “wrapped” to make them callable from other languages.

LISP: LISt Processor (1958)

Rather than being application-specific, LISP embodied essential programming concepts; it was the computer scientist’s language and the first functional programming language (You’ll learn about functional programming in this book). The tradeoff for its power and flexibility was efficiency: LISP was typically too expensive to run on early machines, and only in recent decades have machines become fast enough to produce a resurgence in the use of LISP. For example, the GNU Emacs editor is written entirely in LISP, and can be extended using LISP.

ALGOL: ALGOrithmic Language (1958)

Arguably the most influential of the 1950’s languages because it introduced syntax that persisted in many subsequent languages. For example, C and its derivatives are “ALGOL-like” languages.

COBOL: COmmon Business-Oriented Language (1959)

Designed for business, finance, and administrative data processing. It has an English-like syntax, and was intended to be self-documenting and highly readable. Although this intent generally failed—COBOL is famous for bugs introduced by a misplaced period—the US Department of Defense forced widespread adoption on mainframe computers, and systems are still running (and requiring maintenance) today.

BASIC: Beginners’ All-purpose Symbolic Instruction Code (1964)

This was one of the early attempts to make programming accessible. While very successful, its features and syntax were limited, so it was only partly helpful for people who needed to learn more sophisticated languages. It is predominantly an interpreted language, which means that to run it you need the original code for the program. Despite that, many useful programs were written in BASIC, in particular as a scripting language for Microsoft’s “Office” products. BASIC might even be thought of as the first “open” programming language, as people made numerous variations of it.

Simula 67, the Original Object-Oriented Language (1967)

A simulation typically involves many “objects” interacting with each other. Different objects have different characteristics and behaviors. Languages that existed at the time were awkward to use for simulations, so Simula (another “ALGOL-like” language) was developed to provide direct support for creating simulation objects. It turns out that these ideas are also useful for general-purpose programming, and this was the genesis of Object-Oriented (OO) languages.

Pascal (1970)

Pascal increased compilation speed by restricting the language so it could be implemented as a single-pass compiler. The language forced the programmer to structure their code in a particular way and imposed somewhat awkward and less-readable constraints on program organization. As processors became faster, memory cheaper, and compiler technology better, the impact of these constraints became too costly.

An implementation of Pascal, Turbo Pascal from Borland, initially worked on CP/M machines and then made the move to early MS-DOS (precursor to Windows), later evolving into the Delphi language for Windows. By putting everything in memory, Turbo Pascal compiled at lightning speeds on very underpowered machines, dramatically improving the programming experience. Its creator, Anders Hejlsberg, later went on to design both C# and TypeScript.

Niklaus Wirth, the inventor of Pascal, created subsequent languages: Modula, Modula-2 and Oberon. As the name implies, Modula focused on dividing programs into modules, for better organization and faster compilation. Most modern languages support separate compilation and some form of module system.

C (1972)

Despite the increasing number of higher-level languages, programmers were still writing assembly language. This is often called systems programming, because it is done at the level of the operating system, but it also includes embedded programming for dedicated physical devices. This is not only arduous and expensive (Bruce began his career writing assembly language for embedded systems), but it isn’t portable—assembly language can only run on the processor it is written for. C was designed to be a “high-level assembly language” that is still close enough to the hardware that you rarely need to write assembly. More importantly, a C program runs on any processor with a C compiler. C decoupled the program from the processor, which solved a huge and expensive problem. As a result, former assembly-language programmers could be vastly more productive in C. C has been so effective that recent languages (notably Go and Rust) are still attempting to usurp it for systems programming.

Smalltalk (1972)

Designed from the beginning to be purely object-oriented, Smalltalk significantly moved OO and language theory forward by being a platform for experimentation and demonstrating rapid application development. However, it was created when languages were still proprietary, and the entry price for a Smalltalk system could be in the thousands. It was interpreted, so you needed a Smalltalk environment to run programs. Open-source Smalltalk implementations did not appear until after the programming world had moved on. Smalltalk programmers have contributed great insights benefitting later OO languages like C++ and Java.

C++: A Better C with Objects (1983)

Bjarne Stroustrup created C++ because he wanted a better C and he wanted support for the object-oriented constructs he had experienced while using Simula-67. Bruce was a member of the C++ Standards Committee for its first eight years, and wrote three books on C++ including Thinking in C++.

Backwards-compatibility with C was a foundational principle of C++ design, so C code can be compiled in C++ with virtually no changes. This provided an easy migration path—programmers could continue to program in C, receive the benefits of C++, and slowly experiment with C++ features while still being productive. Most criticisms of C++ can be traced to the constraint of backwards compatibility with C.

One of the problems with C was the issue of memory management. The programmer must first acquire memory, then run an operation using that memory, then release the memory. Forgetting to release memory is called a memory leak and can result in using up the available memory and crashing the process. The initial version of C++ made some innovations in this area, along with constructors to ensure proper initialization. Later versions of the language have made significant improvements in memory management.

Python: Friendly and Flexible (1990)

Python’s designer, Guido Van Rossum, created the language based on his inspiration of “programming for everyone.” His nurturing of the Python community has given it the reputation of being the friendliest and most supportive community in the programming world. Python was one of the first open-source languages, resulting in implementations on virtually every platform including embedded systems and machine learning. Its dynamism and ease-of-use makes it ideal for automating small, repetitive tasks but its features also support the creation of large, complex programs.

Python is a true “grass-roots” language; it never had a company promoting it and the attitude of its fans was never to push the language, but simply to help anyone learn it who wants to. The language continues to steadily improve, and in recent years its popularity has skyrocketed.

Python may have been the first mainstream language to combine functional and OO programming. It predated Java with automatic memory management using garbage collection (you typically never have to allocate or release memory yourself) and the ability to run programs on multiple platforms.

Haskell: Pure Functional Programming (1990)

Inspired by Miranda (1985), a proprietary language, Haskell was created as an open standard for pure functional programming research, although it has also been used for products. Syntax and ideas from Haskell have influenced a number of subsequent languages including Kotlin.

Java: Virtual Machines and Garbage Collection (1995)

James Gosling and his team were given the task of writing code for a TV set-top box. They decided they didn’t like C++ and instead of creating the box, created the Java language. The company, Sun Microsystems, put an enormous marketing push behind the free language (still a new idea at the time) to attempt domination of the emerging Internet landscape.

This perceived time window for Internet domination put a lot of pressure on Java language design, resulting in a significant number of flaws (The book Thinking in Java illuminates these flaws so readers are prepared to cope with them). Although Java was remarkably successful, an important Kotlin design goal is to fix Java’s flaws so programmers can be more productive. Brian Goetz at Oracle, the current lead developer of Java, has made remarkable and surprising improvements in Java despite the constraints he inherited.

Java’s success came from two innovative features: a virtual machine andgarbage collection. These were available in other languages—for example, LISP, Smalltalk and Python have garbage collection and UCSD Pascal ran on a virtual machine—but they were never considered practical for mainstream languages. Java changed that, and in doing so made programmers significantly more productive.

A virtual machine is an intermediate layer between the language and the hardware, so the language doesn’t have to generate machine code for a particular processor; it only needs to generate an intermediate language that runs on the virtual machine. Virtual machines require processing power and, before Java, were believed to be impractical. The Java Virtual Machine (JVM) gave rise to Java’s slogan “write once, run everywhere.” In addition, other languages can be more easily developed by targeting the JVM; examples include Groovy, a Java-like scripting language, and Clojure, a version of LISP.

Garbage collection solves the problem of forgetting to release memory. There are also times when it can be quite difficult to know when a piece of storage is no longer used. Projects have been significantly delayed or even cancelled because of memory leaks. Although garbage collection appears in some prior languages, it was believed to produce an unacceptable amount of overhead until Java showed that it could be practical.

JavaScript: Java in Name Only (1995)

The original Web browser simply copied and displayed pages from a Web server. Web browsers proliferated, becoming a new programming platform that needed language support. Java wanted to be this language but was too awkward for the job. JavaScript began as LiveScript and was built into NetScape Navigator, one of the first Web browsers. Renaming it to JavaScript was a marketing ploy by NetScape, as the language has only a vague similarity to Java.

As the Web took off, JavaScript became tremendously important. However, the behavior of JavaScript was so unpredictable that Douglas Crockford wrote a book with the tongue-in-cheek title JavaScript, the Good Parts, where he demonstrated all the problems with the language so programmers could avoid them. Subsequent improvements by the ECMAScript committee changed JavaScript so thoroughly that it would be unrecognizeable by an original JavaScript programmer. It is now considered a stable and mature language.

Scala: SCALAble (2003)

Martin Odersky created Scala to run on the Java virtual machine: To piggyback on the work done on the JVM, to interact with Java programs, and possibly with the idea that it might displace Java. As a researcher, Odersky and his team used Scala as a platform to experiment with language features, notably those not included in Java.

These experiments have been illuminating and a number of them found their way into Kotlin, usually in a modified form. For example, the ability to redefine operators like + for use in special cases is called operator overloading. This was included in C++ but not Java. Scala added operator overloading but also allows you to invent new operators by combining any sequence of characters. This often produces confusing code. A limited form of operator overloading is included in Kotlin, but you can only overload operators that already exist.

Scala is also an object-functional hybrid, like Python but with a focus on pure functions and strict objects. This helped inspire Kotlin’s choice to also be an object-functional hybrid.

Like Scala, Kotlin runs on the JVM but it interacts with Java far more easily than Scala does. In addition, Kotlin targets JavaScript, the Android OS, and it generates native code for other platforms.

Atomic Kotlin evolved from the ideas and material in Atomic Scala.

Why Kotlin? (Introduced 2011, Version 1.0: 2016)

Just as C++ was initially intended to be “a better C,” Kotlin was initially oriented towards being “a better Java.” It has since evolved significantly beyond that goal.

Kotlin’s design philosophy sets it apart from virtually all its predecessors, because it explicitly avoids inventing new language features to solve perceived problems. Instead, it chooses the most successful and helpful features from other programming languages—after those features have been field-tested and proven to be especially valuable.

Thus, if you are coming from another language, you might recognize some features of that language in Kotlin. This is intentional: Kotlin maximizes productivity by leveraging tested concepts.

This atom does not assume you are a programmer, which makes it hard to explain most of the benefits of Kotlin over the alternatives. There are, however, two topics which are very impactful and can also be explained at this early juncture: Java interoperability and the issue of indicating “no value.”

Effortless Java Interoperability

To be “a better C,” C++ must be backwards compatible with the syntax of C, but Kotlin does not have to be backwards compatible with the syntax of Java—it only needs to work with the JVM. This frees the Kotlin designers to create a much cleaner and more powerful syntax, without the visual noise and complication that clutters Java.

For Kotlin to be “a better Java,” the experience of trying it must be pleasant and frictionless, so Kotlin enables effortless integration with existing Java projects. You can write a small piece of Kotlin functionality and slip it in amidst your existing Java code. The Java code doesn’t even know the Kotlin code is there—it just looks like more Java code.

Companies often investigate a new language by building a standalone program with that language. Ideally, this program is beneficial but nonessential, so if the project fails it can be terminated with minimal damage. Not every company wants to spend the kind of resources necessary for this type of experimentation. Because Kotlin seamlessly integrates into an existing Java system (and benefits from that system’s tests), it becomes very cheap or even free to try Kotlin to see whether it’s a good fit.

In addition, JetBrains, the company that creates Kotlin, provides IntelliJ IDEA in a “Community” (free) version, which includes support for both Java and Kotlin along with the ability to easily integrate the two. It even has a tool that takes Java code and (mostly) rewrites it to Kotlin.

Appendix B covers Java interoperability.

Representing Emptiness

An especially beneficial Kotlin feature is its solution to a challenging programming problem.

What do you do when someone hands you a dictionary and asks you to look up a word that doesn’t exist? You could guarantee results by making up definitions for unknown words. A more useful approach is just to say, “There’s no definition for that word.” This demonstrates a significant problem in programming: How do you indicate “no value” for a piece of storage that is uninitialized, or for the result of an operation?

The null reference was invented in 1965 for ALGOL by Tony Hoare, who later called it “my billion-dollar mistake.” One problem was that it was too simple—sometimes being told a room is empty isn’t enough; you might need to know, for example, why it is empty. This leads to the second problem: the implementation. For efficiency’s sake, it was typically just a special value that could fit in a small amount of memory, and what better than the memory that had already been allocated for that information?

The original C language did not automatically initialize storage, which caused numerous problems. C++ improved the situation by setting newly-allocated storage to all zeroes. Thus, if a numerical value isn’t initialized, it is simply a numerical zero. This didn’t seem so bad but it allowed uninitialized values to quietly slip through the cracks (newer C and C++ compilers often warn you about these). Worse, if a piece of storage was a pointer—used to indicate (“point to”) another piece of storage—a null pointer would point at location zero in memory, which is almost certainly not what you want.

Java prevents accesses to uninitialized values by reporting the error when the program is running (that is, at runtime). Although this discovers uninitialized values, it doesn’t solve the problem because the only way you can verify that your program won’t crash is by running it. There are swarms of these kinds of bugs in Java code, and programmers waste huge amounts of time finding them.

Kotlin solves this problem by preventing operations that might cause null errors before the program can run. This is the single-most celebrated feature by Java programmers adopting Kotlin. This one feature can minimize or eliminate Java’s null errors.

An Abundance of Benefits

The two features we were able to explain here (without requiring more programming knowledge) make a huge difference whether or not you’re a Java programmer. If Kotlin is your first language and you end up on a project that needs more programmers, it is much easier to recruit one of the many existing Java programmers into Kotlin.

Kotlin has many other benefits, which we cannot explain until you know more about programming. That’s what the rest of the book is for.

Languages are often selected by passion, not reason…I’m trying to make Kotlin a language that is loved for a reason.—Andrey Breslav, Kotlin Lead Language Designer.

选自《Atomic Kotlin》。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI天才研究院

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值