What's new in Kotlin 2.1.0-RC2
The Kotlin 2.1.0-RC2 release is out! This document contains some details about this EAP release.
IDE support
The Kotlin plugins that support 2.1.0-RC2 are bundled in the latest IntelliJ IDEA and Android Studio. You don't need to update the Kotlin plugin in your IDE. All you need to do is to change the Kotlin version to 2.1.0-RC2 in your build scripts.
See Update to a new release for details.
Language
After the Kotlin 2.0.0 release with the K2 compiler, the Kotlin team at JetBrains is focusing on improving the language with new features. In this release, we are excited to announce several new language design features.
These features are available in preview, and we encourage you to try them and share your feedback:
Guard conditions in
when
with a subject. Read the KEEP document for detailsMultidollar interpolation: improved handling of
$
in string literals. Read the KEEP document for details
See the full list of Kotlin language design features and proposals.
Non-local break and continue
Kotlin 2.1.0-RC2 introduces a preview of a new feature, an ability to use non-local break
and continue
. It reduces boilerplate code and adds more flexibility when working with inline functions.
Previously, you could only use non-local returns in your project. Now, Kotlin also supports break
and continue
jump expressions non-locally. That means that you can apply them within lambdas passed as arguments to an inline function that encloses the loop:
The feature is currently Experimental. To try it out in your project, use the -Xnon-local-break-continue
compiler option in the command line:
Or set it in the compilerOptions {}
block of your Gradle build file:
We're planning to make this feature stable in future Kotlin releases. If you encounter any issues when using non-local break
and continue
, please report them to our issue tracker.
Support for requiring opt-in to extend APIs
Kotlin 2.1.0-RC2 introduces the @SubclassOptInRequired
annotation. This annotation allows library authors to require explicit opt-in before users can implement experimental interfaces or extend experimental classes.
This feature can be useful when a library API is stable enough to use but might evolve with new abstract functions, making it unstable for inheritance.
To add the opt-in requirement to an API element, use the @SubclassOptInRequired
annotation with a reference to the annotation class:
In this example, the CoreLibraryApi
interface requires users to opt in before they can implement it. A user can opt in like this:
For a real-world example of how to use the @SubclassOptInRequired
annotation in your API, check out the SharedFlow
interface in the kotlinx.coroutines
library.
Improved overload resolution for functions with generic types
Previously, if you had a number of overloads for a function where some have value parameters of generic type and others had function types at the same position, the resolution behavior was inconsistent in some cases.
This led to different behavior depending on whether your overloads were member functions or extension functions. For example:
In the example, the KeyValueStore
class has two overloads for the store()
function, where one overload has function parameters with generic types K
, V
, and another has a lambda function that returns a generic type V
. Similarly, there are two overloads for the extension function: storeExtension()
.
When you called the store()
function with and without a lambda function, the compiler successfully resolved the correct overloads. However, when you called the extension function storeExtension()
with a lambda function, the compiler didn't resolve the correct overload because it incorrectly considered both overloads as applicable.
To fix this problem, we've introduced a new heuristic so that the compiler can discard a possible overload when a function parameter with generic type can't accept a lambda function based on information from a different argument. This change makes the behavior of member functions and extension functions consistent, and is enabled by default in Kotlin 2.1.0-RC2.
Improved exhaustiveness checks for when expressions with sealed classes
In previous versions of Kotlin, the compiler required an else
branch in when
expressions for type parameters with sealed upper bounds, even when all cases in the sealed class
hierarchy were covered. This behavior is addressed and improved in Kotlin 2.1.0-RC2, making exhaustiveness checks more powerful and allowing you to remove redundant else
branches. This keeps when
expressions cleaner and more intuitive.
Here's an example demonstrating the change:
Kotlin K2 compiler
With Kotlin 2.1.0-RC2, the K2 compiler now provides more flexibility when working with compiler checks and warnings, as well as improved support for the kapt plugin.
Extra compiler checks
With Kotlin 2.1.0-RC2, you can now enable additional checks in the K2 compiler. These are extra declaration, expression, and type checks that are usually not crucial for compilation, but can still be useful if you want to validate the following cases:
Check type | Comment |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
| A parameter is passed in the lambda expression but never used |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| Code statement is present, but can never been executed |
If the check is true, you'll receive a compiler warning with a suggestion on how to fix the problem.
Extra checks are disabled by default. To enable them, use the -Wextra
compiler option in the command line or specify extraWarnings
in the compilerOptions {}
block of your Gradle build file:
For more information on how to define and use options, see Compiler options in the Kotlin Gradle plugin.
Global warning suppression
In 2.1.0-RC2, the Kotlin compiler has received a highly requested feature, the ability to suppress warnings globally.
Now you can suppress specific warnings in the whole project. To do that, use the -Xsuppress-warning=WARNING_NAME
syntax in the command line or the freeCompilerArgs
attribute in the compilerOptions {}
block of your build file.
For example, if you have extra compiler checks enabled in your project, but want to suppress one of them, use:
To get the warning name, select the problematic element and click the light bulb icon (or use Cmd + Enter/Alt + Enter):
The new compiler option is currently Experimental. Mind the following nuances:
Error suppression is not allowed.
If you pass an unknown warning name, the compilation will result in an error.
You can also specify several warnings at once:
Improved K2 kapt implementation
Currently, projects using the kapt plugin work with the K1 compiler by default, supporting Kotlin versions up to 1.9.
In Kotlin 1.9.20, we launched an experimental implementation of the kapt plugin with the K2 compiler (K2 kapt). Now, we improve K2 kapt's internal implementation to mitigate technical and performance issues.
While the new K2 kapt implementation doesn't introduce new features, its performance has significantly improved compared to the previous K2 kapt implementation. Additionally, the K2 kapt plugin's behavior is now much closer to K1 kapt.
To use the new K2 kapt plugin implementation, enable it the same way as the previous K2 kapt plugin. Add the following flag to the gradle.properties
file of your project:
In upcoming releases, the K2 kapt implementation will be enabled by default instead of K1 kapt, so you won't longer need to enable it manually.
When using the K2 kapt plugin, you may encounter a compilation error during the kaptGenerateStubs*
tasks, even though the actual error details are missing from the Gradle log. This is a known issue that occurs when kapt is enabled in a module, but no annotation processors are present. The workaround is to disable the kapt plugin in the module.
We highly appreciate your feedback before the new implementation is stabilized.
Kotlin Multiplatform
Kotlin 2.1.0-RC2 focuses on the improvements around Gradle: stabilizes new DSL for configuring compiler options in multiplatform projects and introduces a preview of Isolated Projects feature.
New Gradle DSL for compiler options in multiplatform projects is stable
In Kotlin 2.0.0, we introduced a new Experimental Gradle DSL to simplify the configuration of compiler options across your multiplatform projects. In Kotlin 2.1.0-RC2, this DSL has been promoted to Stable.
With this new DSL, you can configure compiler options at the extension level for all targets and shared source sets like commonMain
, as well as at the target level for specific targets:
The overall project configuration now has three layers. The highest is the extension level, then the target level, and the lowest is the compilation unit (which is usually a compilation task):
The settings at a higher level are used as a convention (default) for a lower level:
The values of extension compiler options are the default for target compiler options, including shared source sets, like
commonMain
,nativeMain
, andcommonTest
.The values of target compiler options are used as the default for compilation unit (task) compiler options, for example,
compileKotlinJvm
andcompileTestKotlinJvm
tasks.
In turn, configurations made at a lower level override related settings at a higher level:
Task-level compiler options override related configurations at the target or the extension level.
Target-level compiler options override related configurations at the extension level.
When configuring your project, keep in mind that some old ways of setting up compiler options have been deprecated.
Preview Gradle's Isolated Projects in Kotlin Multiplatform
In Kotlin 2.1.0-RC2, you can preview Gradle's Isolated Projects feature in your multiplatform projects.
The Isolated Projects feature in Gradle improves build performance by "isolating" individual Gradle projects from each other. Each project's build logic is restricted from directly accessing the mutable state of other projects, allowing them to safely run in parallel. To support this feature, we made some changes to the Kotlin Gradle plugin's model, and we are interested in hearing about your experiences during this preview phase.
There are two ways to enable the Kotlin Gradle plugin's new model:
Option 1: Testing compatibility without enabling Isolated Projects: To check compatibility with the Kotlin Gradle plugin's new model without enabling the Isolated Projects feature, add the following Gradle property in the
gradle.properties
file of your project:kotlin.kmp.isolated-projects.support=enableOption 2: Testing with Isolated Projects enabled: Enabling the Isolated Projects feature in Gradle automatically configures the Kotlin Gradle plugin to use the new model. To enable the Isolated Projects feature, set the system property. In this case, you don't need to add the Gradle property for the Kotlin Gradle plugin to your project.
Kotlin/Native
Kotlin 2.1.0-RC2 includes an upgrade for the iosArm64
target support, improved cinterop caching process, and other updates.
iosArm64 is promoted to Tier 1
The iosArm64
target, which is crucial for Kotlin Multiplatform development, has been promoted to Tier 1. It's the highest level of support in the Kotlin/Native compiler.
This means the target is regularly tested on CI to ensure that it's able to compile and run. We also provide source and binary compatibility between compiler releases for it.
For more information on target tiers, see Kotlin/Native target support.
LLVM update from 11.1.0 to 16.0.0
In Kotlin 2.1.0-RC2, we updated LLVM from version 11.1.0 to 16.0.0. The new version includes LLVM bug fixes and security updates. In certain cases, it also brings compiler optimizations and faster compilation.
If you have Linux targets in your project, mind that the Kotlin/Native compiler now uses the lld
linker by default for all Linux targets.
This update shouldn't affect your code, but if you encounter any issues, please report them to our issue tracker.
Changes to caching in cinterop
In Kotlin 2.1.0-RC2, we're making changes to the cinterop caching process. It no longer has the CacheableTask
annotation type. The recommended approach now is to use the cacheIf
output type to cache the results of the task.
This should fix the issue when changes to header files specified in the definition file were not recognized by UP-TO-DATE checks, so the build system failed to recompile the code.
Kotlin/Wasm
Support for incremental compilation
Previously, when you changed something to your Kotlin code, the Kotlin/Wasm toolchain had to recompile the entire codebase.
Starting from 2.1.0-RC2, incremental compilation is supported for the Wasm targets. In development tasks, the compiler now recompiles only files relevant to changes from the last compilation, which noticeably reduces the compilation time.
This change doubles the development speed for now, with plans to improve it further in future releases.
In the current setup, incremental compilation for the Wasm targets is disabled by default. To enable incremental compilation, add the following line to your project's local.properties
or gradle.properties
file:
Try out the Kotlin/Wasm incremental compilation and share your feedback! Your insights will help make this feature stable and default sooner.
Browser APIs moved to the kotlinx-browser stand-alone library
Before, the declarations for Web APIs and related target utilities were part of the Kotlin/Wasm standard library.
In this release, the org.w3c.*
declarations have been moved from the Kotlin/Wasm standard library to the new kotlinx-browser library. This library also includes other web-related packages, such as org.khronos.webgl
, kotlin.dom
, and kotlin.browser
.
This separation provides modularity, enabling independent updates for web-related APIs outside of Kotlin's release cycle. Additionally, the Kotlin/Wasm standard library now contains only declarations available in any JavaScript environments.
To use the declarations from the moved packages, you need to add the kotlinx-browser
dependency in your project's build configuration file:
Improved debugging experience for Kotlin/Wasm
Previously, when debugging Kotlin/Wasm code in web browsers, you might encounter a low-level representation of variable values in the debugging interface. This often made it challenging to track the current state of the application.
To improve this experience, custom formatters have been added in the variable view. The implementation uses the custom formatters API, which is supported across major browsers like Firefox and Chromium-based.
With this change, you can now display and locate variable values in a more user-friendly and comprehensible manner.
To try the new debugging experience:
Add the following compiler argument to the
wasmJs
compiler options:kotlin { wasmJs { … compilerOptions { freeCompilerArgs.add("-Xwasm-debugger-custom-formatters") } } }Enable the Custom formatters feature in your browser.
In the Chrome DevTools, it's placed in Settings | Preferences | Console:
In the Firefox Developer Tools, it's placed in Settings | Advanced settings:
Reduced size of Kotlin/Wasm binaries
The size of your Wasm binaries produced by production builds will be reduced by up to 30%, and you may see some performance improvements. This is due to the fact that Binaryen options --closed-world
, --type-ssa
, and --type-merging
are now considered safe to use for all Kotlin/Wasm projects and are enabled by default.
Improved JavaScript array interoperability in Kotlin/Wasm
While Kotlin/Wasm's standard library provides the JsArray<T>
type for JavaScript arrays, there was no direct method to transform JsArray<T>
into Kotlin's native Array
or List
types.
This gap required creating custom functions for array transformations, complicating interoperability between Kotlin and JavaScript code.
This release introduces an adapter function that automatically converts JsArray<T>
to Array<T>
and vice versa, simplifying array operations.
Here's an example of conversion between generic types: Kotlin List<T>
and Array<T>
to JavaScript JsArray<T>.
Similar methods are available for converting typed arrays to their Kotlin equivalents (for example, IntArray
and Int32Array
). For detailed information and implementation, see the kotlinx-browser
repository.
Here's an example of conversion between typed arrays: Kotlin IntArray
to JavaScript Int32Array
.
Support for accessing JavaScript exception details in Kotlin/Wasm
Previously, when a JavaScript exception occurred in Kotlin/Wasm, the JsException
type provided only a generic message without details from the original JavaScript error.
Starting from Kotlin 2.1.0-RC2, you can now configure JsException
to include the original error message and stack trace by enabling a specific compiler flag, providing more context to help diagnose issues originating from JavaScript.
This behavior depends on the WebAssembly.JSTag
API, which is available only in certain browsers:
Chrome: Supported from version 115
Firefox: Supported from version 129
Safari: Not yet supported
This feature is disabled by default. To enable this feature, add the following compiler flag to your build.gradle.kts
file:
Here’s an example demonstrating the new behavior:
With the -Xwasm-attach-js-exception
flag enabled, JsException
provides specific details from the JavaScript error. Without the flag, JsException
includes only a generic message stating that an exception was thrown while running JavaScript code.
Deprecation of default exports
As part of the migration towards named exports, an error was previously printed to the console when using a default import for Kotlin/Wasm exports in JavaScript.
In 2.1.0-RC2, default imports are completely removed in order to fully support named exports.
When coding in JavaScript for the Kotlin/Wasm target, you now need to use the corresponding named imports instead of default imports.
This change marks the last phase of a deprecation cycle to migrate towards named exports:
In version 2.0.0: A warning message was printed to the console, explaining that exporting entities via default exports is deprecated.
In version 2.0.20: An error occurred, requesting the use of the corresponding named import.
In version 2.1.0: The use of default imports is completely removed.
Support for non-identifier characters in Kotlin/JS properties
Kotlin/JS previously did not allow using names for test methods with spaces enclosed in backticks.
Similarly, it was not possible to access JavaScript object properties that contained characters not permitted in Kotlin identifiers, such as hyphens or spaces:
This behavior differed from JavaScript and TypeScript, which allow such properties to be accessed using non-identifier characters.
Starting from Kotlin 2.1.0-RC2, this feature is enabled by default. Kotlin/JS now allows you to use the backquote syntax and the @JsName
annotation to interact with JavaScript properties that contain non-identifier characters and to use names for test methods.
Now, you can enclose property names in backticks (``) to reference non-identifier characters. Additionally, you can use the @JsName
and @JsQualifier
annotations to map Kotlin property names to JavaScript equivalents:
Gradle improvements
Kotlin 2.1.0-RC2 is fully compatible with Gradle 7.6.3 through 8.6. Gradle versions 8.7 to 8.10 are also supported, with only one exception: If you use the Kotlin Multiplatform Gradle plugin, you may see deprecation warnings in your multiplatform projects calling the withJava()
function in the JVM target. We plan to fix this issue as soon as possible.
For more information, see the issue in YouTrack.
You can also use Gradle versions up to the latest Gradle release, but if you do, keep in mind that you may encounter deprecation warnings or some new Gradle features might not work.
Bumped the minimum supported AGP version to 7.3.1
Starting with Kotlin 2.1.0-RC2, the minimum supported Android Gradle plugin version is 7.3.1.
Bumped the minimum supported Gradle version to 7.6.3
Starting with Kotlin 2.1.0-RC2, the minimum supported Gradle version is 7.6.3.
Compose compiler updates
Support for multiple stability configuration files
Compose compiler is able to interpret multiple stability configuration files, but the stabilityConfigurationFile
option of the Compose Compiler Gradle plugin is only allowed for a single file to be specified.
In Kotlin 2.1.0-RC2, this functionality was reworked to allow you to use several stability configuration files for a single module:
The
stabilityConfigurationFile
option is deprecated.There is a new option,
stabilityConfigurationFiles
with the typeListProperty<RegularFile>
.
Here's how you can pass several files to the Compose compiler using the new option:
How to update to Kotlin 2.1.0-RC2
Starting from IntelliJ IDEA 2023.3 and Android Studio Iguana (2023.2.1) Canary 15, the Kotlin plugin is distributed as a bundled plugin included in your IDE. This means that you can't install the plugin from JetBrains Marketplace anymore. The bundled plugin supports upcoming Kotlin EAP releases.
To update to the new Kotlin EAP version, change the Kotlin version to 2.1.0-RC2 in your build scripts.