JetBrains has released Kotlin 2.0 along with the new K2 compiler. While the language itself introduces no new syntax, the K2 compiler brings several benefits, including faster builds, extended language capabilities with smart casts, and multiplatform support out of the box.
This release introduces the K2 compiler, unifying all platforms that Kotlin supports, as all compiler backends now share a lot of logic and a unified pipeline. This allows us to implement most features, optimizations, and bug fixes once for all platforms, drastically increasing the development speed of new language features.
K2 currently supports four backends: JVM, JavaScript, Wasm, and native. One of the benefits of targeting all platforms through the same compiler is the possibility to support multiplatform library development easily through the definition of a new format for multi-platform library distribution which will enable the creation of universal Kotlin libraries from any host.
Additionally, as Michail Zarečenskij explained in his Kotlin 2.0 talk at the Kotlin 2024 Conference, multiplatform support came about piecemeal, which made support for the different platforms hard to maintain and evolve.
On the performance front, K2 significantly speeds up compilation time for real world project. JetBrains says K2 doubles compilation speed on average, with some projects compiling faster and others compiling slower than that. The speedup is mostly related to improvement in the initialization phase, which is up to 488% faster, and the analysis phase, which is up to 376% quicker.
Besides performance and multiplatform support, another key reason to switch to a new compiler was to make the language smarter when interpreting developers' intentions with their code.
This was achieved by making the Frontend Intermediate Representation (FIR) support earlier desugaring, so the compiler has more chances to analyze the code; implementing a phased approach to analysis across imports, annotations, and types, which brings more opportunities to integrate IDEs and compiler plugins; and bringing in a new control flow engine with improvements to type inference and resolution. The new control flow engine helps detect unusual code, bugs and other potential issues, thus contributing to the language safety.
As a point in case of the improvements to the language expressiveness these changes bring, Kotlin 2.0 now better supports combinations of operators and numeric conversions. For example, the statement longList[0] += 1
is now allowed and also works in combination with nullable values and the optional dereferencing operator ?
.
Control flow is one of the main tasks of developers today, says Zarečenskij. This is the reason why JetBrains focused on extending the capabilities of the language (syntax) to inspect data and describe conditions, with the effect of improving readability and removing layers of nesting. Additionally, he says, smart casts reduce cognitive load since you do not need to learn new constructs.
For example, Kotlin 2.0 will propagate a smart cast on a local variable, as in the following example:
fun petAnimal(animal: Any) {
if (animal is Cat) {
animal.purr()
}
}
Likewise, smart casts will be propagated to save the state about nullability, is
-checks, as
-casts and contracts.
Another case when Kotlin 2.0 applies new smart cast is with variables captured inside closures as read/write. In this case,
Kotlin will continue enhancing its control flow engine by adding features like pattern matching without binding, context-sensitive resolution, generalized ADTs to support even more smart casts, an effect system, and more.
Many of these new features are in the language roadmap for Kotlin 2.1 or 2.2. Covering all of the newly announced features goes beyond the scope of this article, so do not miss the talk at the Kotlin 2024 Conference for the full details.