Kotlin 1.3.50 released
We’re happy to announce the release of Kotlin 1.3.50 today. In addition to the quality and tooling improvements, the main focus for this version has been on:
- Designing a new Duration and Time Measurement API (available for preview).
- Working on an improved Java-to-Kotlin converter.
- Experimental generation of external declarations for npm dependencies in Gradle Kotlin/JS projects (using Dukat).
- A separate plugin for debugging Kotlin/Native code in IntelliJ IDEA Ultimate.
- Java compilation support in multiplatform projects.
Null-check optimizations planned for Kotlin 1.4
As you probably know, Kotlin decreases the possibility of
NullPointerExceptions by providing support for nullable types. However, because of interoperability with Java code, it’s impossible to avoid NPEs completely. To help developers better understand the source of a nullability problem if it occurs, Kotlin compiler throws different types of runtime exceptions with clear error messages instead of pure NPEs. It turned out that this approach has its disadvantages: it reduces possible null check optimizations that can be performed either by the Kotlin compiler or by various kinds of bytecode processing tools, such as the Android R8 optimizer.
To solve this, starting from Kotlin 1.4, all runtime null checks will throw a
java.lang.NullPointerException instead of a
TypeCastException. This applies to: the
!! operator, parameter null checks in the method preamble, platform-typed expression null checks, and the
as operator with a non-null type. This doesn’t apply to
lateinit null checks and explicit library function calls like
Note that from a developer’s perspective, things won’t change that much: the Kotlin code will throw exceptions with the same error messages as before. The type of exception changes, but the information passed stays the same. For instance, the following code currently throws an
IllegalStateException with the error message “JavaCode.getNull() must not be null”:
Right before the
duplicate function call at line
1, a special check is generated which throws this exception if the expression
null. Starting with Kotlin 1.4, this code will throw a
NullPointerException instead with the same message, “JavaCode.getNull() must not be null”.
After this change of behavior, the optimizers will be able to decrease the total number of null-checks present in the bytecode by removing repetitive null-checks when possible: since all checks throw the same NPE exception, only one can remain. During such optimizations, the specific helpful messages of NPEs can be lost, but that’s the price to be paid for the gained performance benefits. Note that these optimizations are still to be implemented in the corresponding tools, and when implemented, there will be more details about that, but the change of the exception type makes it possible in the future.
Standard library changes
Note that all new functions are added to the standard library in the “experimental” state.
Duration and time measurement API
A new duration and time measurement API is available for preview. Duration can be measured in a variety of units: seconds, milliseconds, nanoseconds, etc. The confusion between different units is a known source of bugs: if the API expects the duration stored as primitive value like
Long, one can erroneously pass the value in the wrong unit, and unfortunately the type system doesn’t help prevent that. Creating a regular class to store duration solves this problem, but brings another one: additional allocations.
Inline classes provide a very elegant solution to that: they bring both type system guarantees and an allocation-free approach. Now the API can use the
Duration type, and all the clients will need to specify the time in the desired units explicitly. Since
Duration is declared as an inline class, no extra allocations are happening under the hood:
This release brings support for
MonoClock which represents the monotonic clock. The recommended approach to measuring time duration from a given point in your program is to use the monotonic clock, which doesn’t depend on the system time. System time might be changed outside, and that might lead to erroneous behavior. The monotonic clock can only measure time difference between given time points, but doesn’t know the “current time.”
Clock interface provides a general API for measuring time intervals.
MonoClock is an object implementing
Clock; it provides the default source of monotonic time on different platforms.
When using the
Clock interface, you explicitly mark the time of action start, and later the time elapsed from the start point. It is especially convenient if you want to start and finish measuring time from different functions:
measureTimedValue function allows you to measure the duration of a given action and get its result together with the duration of the elapsed time interval. It measures the elapsed time with
For more details about the implementation of the
Duration class and the details of the
Clock interface and
MonoClock implementations for different platforms, please refer to the corresponding KEEP. Note that this API is experimental and is subject to change based on your feedback. You will need to explicitly give your consent to use it by applying the corresponding annotations.
We’re looking forward to your feedback!
Functions for bit manipulation
The standard library now contains an API for bit manipulation (as usual, in the experimental state initially):
Note that similar extension functions for Int, Long, Short, Byte, and their unsigned counterparts have been added.
IntelliJ IDEA support
Improved Java to Kotlin converter
We plan to improve the Java-to-Kotlin converter to minimize the amount of “red code” one has to fix manually after the conversion. As the current converter almost always generates non-nullable types, you need to fix the nullability issues by hand afterward. It can often lead to runtime errors from nullability mismatch later.
The new, improved version of the Java-to-Kotlin converter tries to infer nullability more correctly based on the Java type usages in the code. Note that there’s no goal to produce 100% error-free code. The goal is to decrease the number of compilation errors and to make the produced Kotlin code more convenient to work with. The new converter fixes many other known bugs, too; for instance, it now correctly handles implicit Java type casts.
In the future, the new converter is going to become the default one. In this release, it’s available for preview. To turn it on, specify the
Use New J2K (experimental) flag in settings.
Please give it a try and share your feedback with us!
We’ve improved how the Kotlin “Variables” view chooses the variables to display. As there’s a lot of additional technical information in the bytecode, the Kotlin “Variables” view highlights only the relevant variables. Now it works better when you set a breakpoint inside a lambda (either inlined or non-inlined). Local variables inside the lambda, as well as captured variables from the outer context and parameters of the outer function, are correctly displayed:
You can now set a breakpoint at the end of the function, if needed:
Support for the “Evaluate expression” functionality in the debugger was improved for many non-trivial language features, such as local extension functions or accessors of member extension properties. Also, you can now modify variables via “Evaluate expression”:
Note that, alternatively, you can modify variables in the “Variables” view directly.
New intentions and inspections
New intentions and inspections have been added. One of the goals of intentions is to help you learn how to write idiomatic Kotlin code. The following intention, for instance, suggests using the
indices property rather than building a range of indices manually:
If the index isn’t used, the loop can be automatically replaced with a for loop over elements.
IntelliJ IDEA now:
- Can automatically replace the
lateinitproperty of a primitive type with the
- Can convert a regular property to a lazy one and back.
- Detects usages of Java methods for array comparison (like
Array.deepEquals()) and suggest replacing them with their Kotlin counterparts (like
- Highlights the deprecated import in the completion list.
The general performance of IDE actions has been improved, and several known situations that were causing the UI to freeze (such as calling the “Move” refactoring on a file with a huge number of usages) have been fixed.
This update adds support for building and running Kotlin/JS Gradle projects using the
org.jetbrains.kotlin.js plugin on Windows. Just like on other platforms, you can build and run your projects using Gradle tasks, dependencies from NPM required in your Gradle configuration are resolved and included, you can try out your applications using webpack-dev-server (e.g. by invoking the
browserRun Gradle task), and more. As with the other platforms, all of this can be used without having to manually install and manage a node, npm, or yarn distribution.
Under the hood, there have also been a series of performance improvements for Kotlin/JS, improving the incremental compilation time for projects. This means that you can expect speedups of up to 30% when compared to 1.3.41.
Our improved integration with NPM means that projects are now resolved lazily and in parallel, and support for projects with transitive dependencies between compilations in the same project has been added.
The new version also brings with it changes in the structure and naming of generated artifacts. Generated artifacts are now bundled in the distributions folder, and they include the version number of the project and
archiveBaseName (which defaults to the project name), e.g.
Dukat allows the automatic conversion of TypeScript declaration files (
.d.ts) into Kotlin external declarations (and thus replaces the
Kotlin/JS now ships with experimental support for dukat integration for Gradle projects. With this integration, by running the build task in Gradle, typesafe wrappers are automatically generated for npm dependencies and can be used from Kotlin.
Because dukat is still in a very early stage, its integration is disabled by default. Add the
kotlin.js.experimental.generateKotlinExternals=true line into the
gradle.properties file in a project root directory to turn on dukat for your project. We’ve prepared an example project for it too, which demonstrates the use of dukat in Kotlin/JS projects. Try it out and share your feedback with us.
It was not easy but possible to notice that the version of Kotlin/Native differed from the version of Kotlin. Not anymore! The version schemes for Kotlin and Kotlin/Native are now aligned. This release uses version 1.3.50 for both Kotlin and Kotlin/Native binaries, reducing the complexity.
This release brings more pre-imported Apple frameworks for all platforms, including macOS and iOS. The Kotlin/Native compiler now includes actual bitcode in produced frameworks.
Several improvements have been made for interop. We now support the
kotlin.Deprecated annotation when producing a framework, and the generated Objective-C headers code will not have warnings. The
getOriginalKotlinClass() function is added into the standard library to get a
KClass from an Objective-C class or protocols.
The standard library has been updated to support the
kotlin.reflect.typeOf() function for Kotlin/Native types. The new function
executeAfter() is added to the
Worker type to execute actions after a delay. In addition, you can call the
processQueue() function on the
Worker to process the tasks queue explicitly.
The older functions
ByteArray.stringFromUtf8OrThrow() are now deprecated. In the previous release, we added the
ByteArray.decodeToString() function (in the
kotlin.text package) to convert a UTF-8 string to a Kotlin string. That function does not support NULL-terminated strings, so to fix that, in 1.3.50 we’ve added a new function to deal with NULL-terminated UTF-8 strings easily. The
ByteArray.toKString() function (from the
kotlinx.cinterop package) can be used to turn a NULL-terminated UTF-8 string into a Kotlin string. You can pass start and end indices to the function if needed.
We’ve deprecated and removed the
kotlin-platform-native Gradle plugin in favor of the
kotlin-multiplatform Gradle plugin, so now you can easily benefit from all multiplatform project features. Check out the documentation for the migration guide and more info
Finally, we are happy to share that the Kotlin/Native compiler and the interop tool performance has been improved in this release.
Java compilation can now be included in Kotlin/JVM targets of a multiplatform project by calling the newly added
withJava() function of the DSL. It will configure Java plugin to use the
src/<targetName>Test/java paths by default. Here is a full example to create a Kotlin/JVM target with enabled Java compilation:
Kotlin’s New Project wizard now generates Gradle Kotlin DSL for new projects.
Debugging Kotlin/Native code in IntelliJ IDEA Ultimate is now supported too! Try installing the new Native Debug for IntelliJ IDEA Ultimate plugin. It should detect Kotlin/Native run configurations and the debug action is supported:
This release adds multiple features and improvements in scripting and REPL support. Using Kotlin as a scripting language for your application is even easier! Now the scripting support works out of the box: we’ve published a default JSR-223 implementation library, so to add Kotlin scripting support for your application, you only need to add
kotlin-scripting-jsr223 as a dependency and use the
javax.script API with Kotlin.
Properties that are set via the JSR-223 API are now accessible from scripts as regular Kotlin properties (before, that you had to use the
kotlin-main-kts artifact, which was introduced in Kotlin 1.3 to simplify the creation and usage of the basic utility scripts, can now be used as a JSR-223 host as well. In addition to the annotations like
DependsOn for resolving dependencies, it now supports the
@Import annotation instructing the scripting compiler to “import” another script into the current one:
How to update
As always, you can try Kotlin online at play.kotl.in.
- In Maven, Gradle, and npm: Use
1.3.50as the version for the compiler and the standard library. See the docs here.
- In IntelliJ IDEA and Android Studio: Update the Kotlin plugin to version 1.3.50. Use Tools | Kotlin | Configure Kotlin Plugin Updates and click the “Check for updates now” button.
- In Eclipse: Install the plugin using the Marketplace.
- The command-line compiler can be downloaded from the Github release page.
We want to especially thank Toshiaki Kameyama for his ongoing work on providing many useful intentions and inspections for IntelliJ IDEA.
We’d like to thank all our external contributors whose pull requests were included in this release:
* Steven Schäfer
* Ivan Gavrilovic
* Mads Ager
* Ting-Yuan Huang
* Jiaxiang Chen
* Mark Punzalan
* Jake Wharton
* Jeffrey van Gogh
* Peter Xu
* Benjamin Orsini
* Dereck Bridie
* Eduard Wolf
* George Gastaldi
* Juan Chen
* Kevin Peek
* Louis CAD
* Martin Petrov
* Matthew Runo
* AJ Alt
* Ty Smith
* Dat Trieu