Kotlin 1.3.70 Released
Today we’re happy to present to you the latest version of Kotlin – 1.3.70.
This incremental release doesn’t provide any major new features. However, we’ve tried our best to improve the existing functionality, fix issues, and even add experimental things for you to try. Here are the highlights of Kotlin 1.3.70:
- New functions and classes for Kotlin collections in the standard library.
- Various improvements in the IntelliJ Kotlin plugin: improved
*.gradle.ktssupport, testing, debugging, completion, and so on.
- The Kotlin/JVM compiler now generates type annotations in the bytecode for Java 8 and later targets.
- Bundle optimizations, npm dependency declarations, and long-awaited new docs for Kotlin/JS.
- Faster compilation and debugging for Kotlin/Native.
- Improved support for scripting in the IDE and command-line tools.
You can find the complete list of changes in the change log. As always, we’d like to thank our external contributors.
Now let’s dive into the details!
Standard library changes
Note that all new functions are added to the standard library in the experimental state.
Extending StringBuilder in the common library
StringBuilder was already present in the common standard library, in the
kotlin.text package. However, many important members were missing or were available only on the JVM. Now, all the JVM
StringBuilder functionality was added to the common
expect class with the corresponding implementations on different platforms. This means you can effectively use
StringBuilder from common code as all the necessary members are there.
Working with KClass
Some basic useful members on
KClass no longer require a
kotlin-reflect dependency on the JVM:
Before, you needed to provide a Kotlin reflection implementation at runtime to make it work. Now you can use these simple members without additional dependencies.
Renaming of experimental annotations (@Experimental and @UseExperimental)
As you may know, Kotlin has a built-in mechanism for using experimental features. It includes annotations from the standard library, which mark declarations that are either experimental themselves or use other experimental declarations. In previous versions, these were
We’ve decided to widen the scope of this mechanism, because something being in the experimental state is not the only reason to require consent for using APIs. For example, an API can be internal or have some restrictions. We have renamed the annotations to reflect this: the names
@RequiresOptIn have replaced
@Experimental, accordingly. The compiler argument
-Xuse-experimental has been renamed to
-Xopt-in. As for
-Xexperimental, we’re dropping it because how rarely it is used and how much it increases complexity. The old declarations
@UseExperimental are still supported in 1.3.70, but will be dropped in 1.4.
Renaming of experimental time measurement API
Another renaming we’ve made concerns the Duration and Time measurement API.
ClockMark have been renamed to
TimeMark, accordingly. The previous names are kept as deprecated type aliases for now.
Double-ended queue implementation: ArrayDeque
We’re happy to add the implementation of the double-ended queue, the
kotlin.collections.ArrayDeque class, to the Kotlin standard library! The community has been asking for it for some time. Even though you could use the
java.util.ArrayDeque class from the Java standard library, there was no common implementation you could use for Kotlin/JS, Kotlin/Native and, most importantly, in common code. Now such an implementation is available, albeit in the experimental state.
A double-ended queue allows you to add/remove elements both to/from the beginning and the end of the queue in amortized constant time:
You can use a double-ended queue by default when you need a queue or a stack in your code.
kotlin.collections.ArrayDeque implementation uses a resizable array underneath: it stores the contents in a circular buffer, an
Array, and resizes this
Array only when it becomes full.
Conceptually, the implementation of
ArrayDeque is very similar to that of
java.util.ArrayDeque. Note, however, that it’s a different implementation and this new implementation will be used when you use this class for Kotlin/JVM. This differs from how it works with other collections: when you create an
ArrayList and compile it to JVM, the
java.util.ArrayList class is used under the hood. Unlike Java’s
ArrayDeque, which implements only the
Collection interface, Kotlin’s
MutableList. This means you can access all the elements by index, which is not possible in Java’s
We’re releasing the
ArrayDeque class now in the experimental state, and are looking forward to your feedback!
Another important new functionality is builder functions for collections:
buildMap. You can use such a builder function to conveniently manipulate a mutable collection during the creation phase and get a read-only collection as a result:
These builder functions are implemented similarly to
buildList takes a lambda with a receiver as an argument. An implicit “this” receiver inside the lambda has the type
buildList returns a read-only List as a result.
It is often more readable and more effective in terms of performance to use the builder functions when you need to perform complicated manipulations, like using conditions, modifying several initial collections and merging the result, and so on. Note that these functions are also currently released in the experimental state.
reduceOrNull() and randomOrNull() counterparts
You know this convention in Kotlin: having a pair of functions, where the first one throws an exception if the operation isn’t possible, and the second one returns
string.toIntOrNull(). Now we’ve added new
reduceOrNull() counterpart functions, following the same convention:
If you use
reduce(), you’ll get an exception if the collection is empty.
We’re adding a new set of functions for working with lists and sequences. They represent the concept of “scanning”; similar functions are already present in different libraries and languages.
scan() is closely related to
fold() apply the given binary operation to the sequence of values, but differ in that
scan() returns the whole sequence of intermediate results, while
fold() returns only the final result.
scan takes an initial accumulator value:
If your result type is the same as an element type and you can use the first element as an initial value, then you can use the
<img class=”alignnone size-full wp-image-7941″ src=”https://blog.jetbrains.com/wp-content/uploads/2020/02/kotlin-scanReduce.png” onmouseover=”this.src=’https://blog.jetbrains.com/wp-content/uploads/2020/02/kotlin-scanReduce.gif‘;”
onmouseout=”this.src=’https://blog.jetbrains.com/wp-content/uploads/2020/02/kotlin-scanReduce.png‘;” alt=”” />
Note that when you use
scanReduce() on sequences, they return sequences as a result, which are lazy by nature. That means that the scanning process only starts when you ask data from the resulting sequence, specifically call a terminal operation (the one returning something other than another sequence), such as
max(). When you use
scanReduce() on lists, they return lists as a result.
Read this KEEP for more details.
IntelliJ IDEA support
This release includes several improvements for Kotlin support in IntelliJ IDEA. Let’s walk through the most interesting ones.
In 1.3.70, we worked to improved IntelliJ IDEA’s support for Gradle Kotlin DSL scripts (
*.gradle.kts files). As a result, the latest version of the Kotlin plugin demonstrates better performance in syntax highlighting, completion, search, and other aspects of working with Kotlin build scripts. A detailed review of improvements is provided in this blog post.
To enjoy all the changes and improvements, make sure to use IntelliJ IDEA 2019.2 or later with Gradle 6.0 or later.
In 1.3.70, we’ve made noticeable improvements for Kotlin code completion in IntelliJ IDEA. Now, completion suggestions include functions declared in objects, including extension functions, object-level overrides, and even functions declared in nested objects.
We’ve also improved the machine learning model that sorts the completions list, and now, the most relevant options appear at the top.
New color schemes
To enable you to change the appearance of Kotlin code in the editor to your liking, we’ve added new customizable color schemes. In particular, now you can set your own color schemes for the suspend function calls and property declarations.
In previous versions, the Kotlin/Native debugger used to have a separate breakpoint type, confusing some users with an unclear choice like “which breakpoint type should I use here?”. Now the single breakpoint type
Kotlin Line Breakpoint works for both JVM and Native targets.
Kotlin/JS and Kotlin/Native tests
Test results for Kotlin/JS and Kotlin/Native are now displayed right in the IntelliJ IDEA, as it has always been for Kotlin/JVM tests. Besides, we’ve fixed test filtering for Kotlin/JS, so you can run individual tests, and Kotlin/Native tests targeting the iOS Simulator can finally also be launched directly by pressing the “Play” button.
Moreover, in IntelliJ IDEA Ultimate, you can start the Kotlin/JS debugging by clicking an icon near the test declaration.
<img class=”alignnone size-full wp-image-7988″ src=”https://blog.jetbrains.com/kotlin/files/2021/02/js-test-debug.png” onmouseover=”this.src=’https://blog.jetbrains.com/kotlin/files/2021/02/js-test-debug.gif‘;”
onmouseout=”this.src=’https://blog.jetbrains.com/kotlin/files/2021/02/js-test-debug.png‘;” alt=”” />
Alternatively, you can start debugging by manually choosing
browserTest task in the Gradle tool window. For
browserRun, you can attach debugger after starting the development server using the Attach to Node.js/Chrome run configuration.
Other notable mentions
There are also other improvements in Kotlin support in IntelliJ IDEA. Here are some worth mentioning:
- Improved performance of file analysis and copy-paste action.
- New inspection on pointless unary operators. They may appear when splitting long expressions onto multiple lines:
- Numerous formatting improvements, including formatting of call chains, line breaks, spacing, and comments.
Kotlin now can generate type annotations in the JVM bytecode (target version 1.8+), so that they become available at runtime. This feature has been requested by the community for some time, because it makes usage of some existing Java libraries much easier, and it gives more power to those authoring new libraries.
In the following example, the
@Foo annotation on the
String type can be emitted to the bytecode and then used by the library code:
To emit the type annotation in the bytecode, follow these steps:
- Make sure that your declared annotation has a proper annotation target (Java’s
AnnotationTarget.TYPE) and retention (
- Compile both the annotation class declaration and the code using this annotation (class A in the example above) to JVM bytecode target version 1.8+. You can specify it with
- Compile the code using the annotation with the
Note that the type annotations from the standard library aren’t emitted in the bytecode for now because they are compiled with the target version 1.6.
So far, only the basic cases are supported:
- Type annotations on method parameters, method return types and property types;
- Invariant projections of type arguments, e.g.
In the future, we’re planning to support generating type annotations for covariant and contravariant type projections and annotations on inner types (such as
Smth<@Ann Outer.Inner>). We believe that the supported cases should already cover most real-life scenarios, but if you need type annotations for more complicated cases, please let us know.
Starting with Kotlin 1.3.70, DCE (Dead Code Elimination) is now readily available through the
org.jetbrains.kotlin.js Gradle plugin and does not need to be manually added. It receives a set of new tasks that you can use to control the optimization and execution of your JS project.
During development, use
browserDevelopmentRun to start a non-optimized run of your application with the bundled development server, and use
browserDevelopmentWebpack to create a non-optimized bundle of your application in the
build/distributions folder. If you choose not to run any optimizations, your build times will be faster, but compiled programs will have larger file sizes.
When preparing for production, use
browserProductionRun to start an optimized run of your application, and use
browserProductionWebpack to generate an optimized bundle that is fit for deployment in production. Production builds take a little longer to compile, but end up with a significantly better-optimized bundle than their development counterparts:
|Project||Development Build (gzip)||Production Build (gzip)|
|“Hello, World”||963 KiB||14 KiB|
|Kotlin/React Example (“CodeQuiz”)||4.1 MiB||345 KiB|
While the previous Gradle tasks
browserRun (now an alias for
browserWebpack (now an alias for
browserProductionWebpack) are currently still available, you should replace them with their newly added equivalents in any of your build scripts.
These Gradle tasks are available for projects using the
kotlin.js Gradle plugins. For
kotlin.js, you can also use the shorter task aliases
If you’d like to learn more about Dead Code Elimination in Kotlin/JS and how to configure it in a fine-grained manner, check out the documentation.
Automatic copying of resources
Build tasks that create bundles in the distributions folder (like
browserProductionWebpack) now also copy all assets from the
resources folder, so it is no longer required to manually copy images, stylesheets, and others to get a deployable set of artifacts.
Smoother support for npm dependency declarations
When using the Kotlin/JS Gradle plugin, it is now possible to declare npm dependencies inside the top-level dependencies block, instead of having to manually add a main source set. This means that the following snippet is now valid:
Experimental test debugging through Gradle
It is now possible to debug tests from within IntelliJ IDEA directly for the Kotlin/JS browser target. To debug a failing test, set a breakpoint in the IDE, and then either start the
check Gradle task in debug mode or use the gutter icons to debug a set of tests. Gradle will execute the test task for the platform, and the debugger will stop at a synthetic breakpoint. It will hit the breakpoint as soon as Gradle shows the
browserTest task in the console:
At this point, switch to the
:browserTest session in the debugger, and select the tab labelled “Debugger”. Click the “Resume Program” button to begin executing your tests:
Currently, this process is necessary to keep the debugger in IntelliJ IDEA in sync with the JS engine. We’re aware that this number of steps to start a debugging session is cumbersome, so keep a lookout in future versions for an even smoother debugging experience!
We also plan to provide the same experience for debugging Kotlin code that targets Node.js after resolving some remaining issues.
We hope that these changes will make it easier for you to get started and work with Kotlin/JS, especially if you want to try it for frontend development. We are committed to constantly improving the documentation and reference materials that help you learn Kotlin/JS. So, if you are still missing any essentials in the documentation or how-to’s, please let us know in the comments.
In 1.3.70, we’re ready to show the first results of our work on optimizing the overall performance of the Kotlin/Native development process. Compile-time performance was one of the known weak points in Kotlin/Native development, so we’ve got two new features to decrease compilation times:
- Now the Kotlin/Native compiler runs directly from the Gradle daemon, so no time is spent on starting a new process and loading the compiler into it on each compilation.
- In the debug mode, the compiler caches project dependencies. Now the first compilation takes a bit longer, but the subsequent ones complete faster. Note that currently, this works only for iOS simulator (iosX64) and macOS (macosX64); we’re still working on this.
We have not forgotten about runtime and debug performance improvements either. In 1.3.70, we’ve cut some time spent on object allocation: now more objects are allocated on a stack (which is faster than heap allocation), and some singleton objects are created at the compile time. The debug process has become faster as well.
Support for multiple Kotlin frameworks in a single application
Previously, there was a known issue that an application could not use more than one dynamic Kotlin/Native framework because Obj-C classes defined in runtime were conflicting, coming from different instances of runtime. We’ve fixed this in 1.3.70, so now an application can use multiple Kotlin/Native frameworks. Any common dependencies are present in the frameworks under different Swift modules (and with different Obj-C prefixes).
Support for vector types
Starting with 1.3.70, Kotlin/Native supports SIMD types. This gives you many more third-party APIs available for using from Kotlin/Native, such as the popular Apple frameworks Accelerate and SpriteKit.
Version 1.3.70 presents a set of improvements that provide a better experience of using Kotlin scripts with IntelliJ IDEA and Kotlin command-line tools.
Additionally, to help you become familiar with Kotlin scripting, we’ve prepared a project with examples. It contains examples of the standard scripts (
*.main.kts) and examples of the scripting API usage and custom script definitions. Please try it and share your feedback in our issue tracker.
kotlin-main-kts support in compiler and IDE
In Kotlin 1.3, we introduced the kotlin-main-kts artifact which simplifies the creation and usage of the basic utility scripts. Now it is loaded by default by the Kotlin compiler and IntelliJ plugin, so that
*.main.kts scripts are supported out of the box. In particular, now you can use such scripts without adding
kotlin-main-kts.jar to the classpath.
In IntelliJ IDEA, this gives you highlighting and navigation, including resolve into dynamic dependencies, for
*.main.kts files, even outside the source directories.
We’ve also improved the performance of the compiled
*.main.kts scripts execution by enabling caching for them to make subsequent runs significantly faster.
We’ve also extended the support for Kotlin scripting in the command line tools.
kotlin runner distributed with the Kotlin command-line compiler now supports script execution. To run a script with
kotlin, just pass the script file name to it:
Such a call will run the script in exactly the same way as if you called the compiler with
.main.kts scripts out of the box.
kotlin runner can also be used for expression evaluation. To evaluate an expression, pass it as a value of the –
You’ll get the result right away.
The same functionality is added to the Kotlin command-line compiler but with a different option name:
How to update
As always, you can try Kotlin online at play.kotl.in.
- In Gradle and Maven: Use
1.3.70as the version for the compiler and the standard library. See the docs for Gradle and for Maven.
- In IntelliJ IDEA and Android Studio: Update the Kotlin plugin to version 1.3.70. Use Tools | Kotlin | Configure Kotlin Plugin Updates and click the “Check again” button.
- In Eclipse: Install the plugin using the Marketplace.
- The command-line compiler can be downloaded from the Github release page.
If you run into any problems with the new release, you’re welcome to ask for help on the forums on Slack (get an invite here), or to report issues in our issue tracker.
We want to thank Fleshgrinder for his work on adding support for builder functions for collections, and adellibovi for adding
Thanks also to all of our external contributors whose pull requests were included in this release:
- Steven Schäfer
- Toshiaki Kameyama
- Mark Punzalan
- Mads Ager
- Kristoffer Andersen
- Ivan Gavrilovic
- Jiaxiang Chen
- Kevin Bierhoff
- Alfredo Delli Bovi
- Tillmann Berg
- Victor Turansky
- Alexander Shustanov
- Leonardo Colman Lopes
- Juan Chen
- Jordan Demeulenaere
- Jim Sproc
- Burak Eregar
- Dmitriy Jarosh
- Dat Trieu
- Dmitry Borodin
- Efeturi Money
- Miguel Serra
- Jens Klingenberg
- Louis CAD
Subscribe to Blog updates
Thanks, we've got you!