Releases

Kotlin 1.6.20 Released

Read this post in other languages:
Français, 한국어, 简体中文

Kotlin 1.6.20 has officially been released. It offers previews of future language features, makes the hierarchical structure the default for multiplatform projects, and brings performance improvements for the JVM, JS, and Native platforms.

In this blog post, you’ll find an overview of the following improvements, along with a complete list of the other evolutionary changes:


How to update

If you use IntelliJ IDEA or Android Studio, you have the option to automatically update to the new Kotlin release as soon as it becomes available.

Update to Kotlin 1.6.20

Major updates

Prototype of context receivers for Kotlin/JVM

With Kotlin 1.6.20, you are no longer limited to having one receiver. If you need more, you can make functions, properties, and classes context-dependent (or contextual) by adding context receivers to their declaration. A contextual declaration does the following:

  • It requires all declared context receivers to be present in a caller’s scope as implicit receivers.
  • It brings declared context receivers into its body scope as implicit receivers.

To enable context receivers in your project, use the -Xcontext-receivers compiler option. You can find a detailed description of the feature and its syntax in the KEEP.

Please note that the implementation is a prototype

  • With -Xcontext-receivers enabled, the compiler will produce pre-release binaries that cannot be used in production code. 
  • The IDE support for context receivers is minimal for now.

Definitely non-nullable types

To provide better interoperability when extending generic Java classes and interfaces, Kotlin 1.6.20 allows you to mark a generic type parameter as definitely non-nullable on the use site with the new syntax T & Any. The syntactic form comes from a notation of intersection types and is now limited to a type parameter with nullable upper bounds on the left side of & and non-nullable Any on the right side:

Set the language version to 1.7 to enable the feature:

Learn more about definitely non-nullable types in the KEEP.

Please note that definitely non-nullable types are in Beta. They are almost stable, but migration steps may be required in the future. We’ll do our best to minimize any changes you have to make.

Support for parallel compilation of a single module in the JVM backend

In Kotlin 1.6.20, we added the experimental JVM IR backend mode to compile all the files in a module in parallel. Parallel compilation can reduce the total compilation time by up to 15%.

Enable the experimental parallel backend mode with the compiler option -Xbackend-threads. Use the following arguments for this option:

  • N is equal to the number of threads you want to use. It should not be greater than your number of CPU cores; otherwise, parallelization stops being effective because of switching context between threads
  • 0 to use one thread for each CPU core

Gradle can run tasks in parallel, but this type of parallelization doesn’t help a lot when a project (or a major part of a project) is just one big task from Gradle’s perspective. If you have a very big monolithic module, use parallel compilation to compile more quickly. If your project consists of lots of small modules and has a build parallelized by Gradle, adding another layer of parallelization may hurt performance because of context switching.

Parallel compilation has some constraints:

  • It doesn’t work with kapt because kapt disables the IR backend.
  • It requires more JVM heap by design. The amount of heap is proportional to the number of threads.

Incremental compilation for development binaries with Kotlin/JS IR compiler

To make Kotlin/JS development with the IR compiler more efficient, we’re introducing a new incremental compilation mode.

When building development binaries with the compileDevelopmentExecutableKotlinJs Gradle task in this mode, the compiler caches the results of previous compilations on the module level. It uses the cached compilation results for unchanged source files during subsequent compilations, making them complete more quickly, especially with small changes. Note that this improvement exclusively targets the development process (shortening the edit-build-debug cycle) and doesn’t affect the building of production artifacts.

To enable incremental compilation for development binaries, add the following line to the project’s gradle.properties:

In our test projects, the new mode made incremental compilation up to 30% faster. However, the clean build in this mode became slower because of the need to create and populate the caches.

Kotlin/Native performance improvements

Kotlin 1.6.20 brings some performance updates and bug fixes that affect the LLVM IR that Kotlin generates. According to the benchmarks on our internal projects, we achieved the following performance boosts on average:

  • 15% reduction in execution time
  • 20% reduction in the code size of both release and debug binaries
  • 26% reduction in the compilation time of release binaries

These changes also provide a 10% reduction in compilation time for a debug binary on a large internal project.

To achieve this, we’ve implemented static initialization for some of the compiler-generated synthetic objects, improved the way we structure LLVM IR for every function, and optimized the compiler caches.

Hierarchical structure support for multiplatform projects

Kotlin 1.6.20 comes with hierarchical structure support enabled by default. Since introducing it in Kotlin 1.4.0, we’ve significantly improved the frontend and made IDE import stable.

Previously, there were two ways to add code in a multiplatform project. The first was to insert it in a platform-specific source set, which is limited to one target and can’t be reused by other platforms. The second is to use a common source set shared across all the platforms that are currently supported by Kotlin.

Now you can share source code among several similar native targets that reuse a lot of the common logic and third-party APIs. The technology will provide the correct default dependencies and find the exact API available in the shared code. This eliminates a complex build setup and having to use workarounds to get IDE support for sharing source sets among native targets. It also helps prevent unsafe API usages meant for a different target.

The technology will come in handy for library authors too, as a hierarchical project structure allows them to publish and consume libraries with common APIs for a subset of targets.
By default, libraries published with the hierarchical project structure are compatible only with hierarchical structure projects. Learn more about project-library compatibility.

Better code-sharing in your project

Without hierarchical structure support, there is no straightforward way to share code across some but not all Kotlin targets. One popular example is sharing code across all iOS targets and having access to iOS-specific dependencies, like Foundation.

Thanks to the hierarchical project structure support, you can now achieve this out of the box. In the new structure, source sets form a hierarchy. You can use platform-specific language features and dependencies available for each target that a given source set compiles to.

For example, consider a typical multiplatform project with two targets — iosArm64 and iosX64 for iOS devices and simulators. The Kotlin tooling understands that both targets have the same function and allows you to access that function from the intermediate source set, iosMain.

The Kotlin toolchain provides the correct default dependencies, like Kotlin/Native stdlib or native libraries. Moreover, Kotlin tooling will try its best to find exactly the API surface area available in the shared code. This prevents such cases as, for example, the use of a macOS-specific function in code shared for Windows.

More opportunities for library authors

When a multiplatform library is published, the API of its intermediate source sets is now properly published alongside it, making it available for consumers. Again, the Kotlin toolchain will automatically figure out the API available in the consumer source set while carefully watching out for unsafe usages, like using an API meant for the JVM in JS code. Learn more about sharing code in libraries.

Configuration and setup

Starting with Kotlin 1.6.20, all your new multiplatform projects will have a hierarchical project structure. No additional setup is required.

  • For Kotlin 1.6.20, we recommend using Android Studio 2021.1.1 (Bumblebee) or later to get the best experience.
  • You can also opt out. To disable hierarchical structure support, set the following options in gradle.properties:

Complete list of improvements

Language

Kotlin/JVM

Kotlin/Native

Kotlin Multiplatform

Kotlin/JS

Security

Gradle

How to install Kotlin 1.6.20

If you already use IntelliJ IDEA or Android Studio, your IDE will suggest updating Kotlin to 1.6.20 automatically. You can also update manually by following these instructions

You can download the latest versions of these IDEs to get extensive support for Kotlin:

  • IntelliJ IDEA – for developing Kotlin applications for various platforms.
  • Android Studio –  for developing Android and cross-platform mobile applications.

Make sure that you have also updated the kotlinx libraries to compatible versions and specified version 1.6.20 of Kotlin in the build scripts of your existing projects.

If you need the command-line compiler, download it from the Github release page.

If you run into any problems

Stay up to date with the latest Kotlin features! Subscribe to receive Kotlin updates by filling out the form to the right of this post.

What else to read and watch