Kotlin Reference
Kotlin Reference
Kotlin Docs 54
Install Kotlin 54
Is anything missing? 58
Kotlin Multiplatform 58
Get started 60
Next steps 62
Kotlin/JS frameworks 64
Kotlin Native 66
Why Kotlin/Native? 66
Target platforms 66
2
Interoperability 67
Interactive editors 68
Libraries 70
Learning Kotlin 76
Language 78
Kotlin/JVM 82
Kotlin/Native 84
Kotlin/JS 86
Gradle 86
Standard library 87
Documentation updates 89
Language 92
Kotlin/JVM 94
Kotlin/Native 95
Kotlin/JS 97
Standard library 98
3
Gradle 103
Language 109
Kotlin/JVM 111
Kotlin/Native 113
Kotlin/JS 119
Security 121
Gradle 123
Language 125
Kotlin/JVM 128
Kotlin/Native 129
Kotlin/JS 132
Tools 137
Kotlin/JVM 143
Kotlin/Native 144
Kotlin/JS 149
Gradle 149
4
Serialization 1.3.0-RC 155
Kotlin/JVM 156
Kotlin/Native 158
Kotlin/JS 159
Gradle 159
Kotlin/JVM 163
Kotlin/Native 166
Kotlin/JS 167
Kotlin/JVM 180
Kotlin/Native 181
Kotlin/JS 181
Kotlin/JVM 184
Kotlin/JS 185
5
Kotlin/Native 187
Kotlin Multiplatform 189
Kotlin/JVM 201
Kotlin/JS 203
Kotlin/Native 204
Kotlin/Native 220
Contracts 221
6
Unsigned integers
225
@JvmDefault 225
Tooling 228
Tools 236
JavaScript 236
7
Install the EAP Plugin for IntelliJ IDEA or Android Studio 253
Functions 259
Variables 259
Comments 261
Ranges 263
Collections 264
Idioms 267
8
Instance checks 268
Read-only list 268
if expression 271
9
Coding conventions 274
Formatting 277
Numbers 291
Booleans 297
Characters 297
Strings 298
Arrays 300
10
Use cases 302
If expression 305
Exceptions 311
Imports 314
Classes 314
Constructors 315
11
Class members 317
Inheritance 317
Inheritance 318
Properties 322
Interfaces 325
Packages 329
12
Class members
330
Modules 331
Extensions 331
Copying 337
Variance 340
13
Anonymous inner classes 348
Members 350
Inheritance 351
Representation 351
Delegation 358
Functions 368
14
Function scope 373
noinline 382
15
Elvis operator 402
Equality 403
Threading 405
Callbacks 406
Coroutines 407
Coroutines 408
Annotations 409
Usage 409
Constructors 410
Instantiation 411
Lambdas 411
16
Repeatable annotations 414
Reflection 416
17
Add a multiplatform dependency 441
18
Get help 487
Targets 488
Compilations 491
19
Publish an Android library 525
Examples 533
Compatibility 540
Workaround to enable IDE support for the shared iOS source set 551
20
Run tests for one or more targets 553
Targets 570
Compilations 582
Dependencies 585
Samples 588
FAQ 592
21
What is Kotlin Multiplatform Mobile? 592
What is Kotlin/Native and how does it relate to Kotlin Multiplatform Mobile? 593
How can I write concurrent code in Kotlin Multiplatform Mobile projects? 595
How can I speed up my Kotlin Multiplatform module compilation for iOS? 595
Be supportive 598
22
Getters and setters 605
Operators 616
Properties 619
Visibility 624
KClass 625
23
Null-safety 627
Variant generics 627
Create a RESTful web service with a database using Spring Boot – tutorial 628
24
Concatenate strings 647
Mutability 657
Covariance 658
Sequences 660
Get the first and the last items of a possibly empty collection 661
25
Platform types 668
Dependencies 680
CSS 685
Node.js 686
Yarn 686
Troubleshooting 689
26
Development server and continuous compilation 692
Output .js files: one per module or one for the whole project 706
Convert JS- and React-related classes and interfaces to external interfaces 708
27
Additional troubleshooting tips when working with the Kotlin/JS IR compiler 711
Example 724
Samples 727
28
Before you start 728
Create a web app draft 732
Bindings 764
29
Mapping primitive data types from C – tutorial 769
30
Receive C string bytes from Kotlin 787
Usage 795
Mappings 795
Subclassing 801
C features 802
Unsupported 803
31
Update Podfile for Xcode 813
32
Create a Kotlin library 831
Threads 841
33
Current and future models 854
Atomics 855
Coroutines 859
Breakpoints 864
Stepping 865
34
How do I run Kotlin/Native behind a corporate proxy? 870
35
Kotlin roadmap by subsystem 895
Copy 906
Iterators 908
Range 911
Progression 911
Sequences 912
Construct 913
Map 918
36
Map 918
Zip 919
Associate 920
Flatten 921
Partition 924
Grouping 925
Slice 926
Chunked 927
Windowed 927
Ordering 931
37
Fold and reduce 935
Filter 945
Distinctions 950
Functions 953
38
Additional references 962
Callbacks 973
Coroutines 978
Concurrency 980
Channels 990
Timeout 1002
39
Composing suspending functions 1004
Buffering 1030
40
Flow exceptions 1037
Channels 1046
Pipelines 1047
Fan-out 1050
Fan-in 1051
CoroutineExceptionHandler 1055
Supervision 1059
41
Thread confinement coarse-grained 1065
Actors 1067
Serialization 1084
Libraries 1084
Formats 1084
Gradle 1091
42
Apply the plugin 1091
OSGi 1108
Maven 1112
Dependencies 1112
43
OSGi 1118
Ant 1118
Targeting JavaScript with single source folder and metaInfo option 1120
References 1120
Differences between "Kotlin coding conventions" and "IntelliJ IDEA default code style" 1123
44
Create and run an application 1134
Gradle 1143
Maven 1144
Gradle 1146
Maven 1146
Gradle 1148
Maven 1148
45
Improving the speed of builds that use kapt 1151
Gradle 1156
Maven 1157
Overview 1159
Resources 1161
46
Comparison to kotlinc compiler plugins 1168
Limitations 1168
Find the actual class or interface declaration that the type alias points to 1169
Types 1172
Misc 1172
Details 1174
Example 1 1183
Example 2 1184
Advanced 1186
47
Avoid the ksp(...) configuration on KSP 1.0.1+ 1187
FAQ 1188
Can I use a newer KSP implementation with an older Kotlin compiler? 1189
Maven 1196
Gradle 1197
FAQ 1197
48
null + null in Kotlin 1198
Strings 1202
FAQ 1213
49
What is Kotlin? 1214
What advantages does Kotlin give me over the Java programming language? 1214
50
Principles of Pragmatic Evolution 1217
Libraries 1220
Language 1226
Language 1228
Tools 1236
Language 1240
Tools 1250
51
Language and stdlib 1253
Tools 1261
Tools 1278
Conclusion 1297
Six key aspects to help you choose between cross-platform app development and the native 1300
approach
When should you choose cross-platform app development? 1302
How do you choose the right cross-platform app development framework for your project? 1306
52
Security
1307
Contribution 1308
53
Kotlin
Docs
Get
started
with
Kotlin
Kotlin is a modern but already mature programming language aimed to make developers happier. It's concise, safe, interoperable with
Java and other languages, and provides many ways to reuse code between multiple platforms for productive programming.
Learn
Kotlin
fundamentals
If you're already familiar with one or more programming languages and want to learn Kotlin, start with these Kotlin learning materials.
If Kotlin is your first programming language, we recommend starting with the Atomic Kotlin book or signing up for the free Kotlin Basics
track on JetBrains Academy.
Install
Kotlin
Kotlin is included in each IntelliJ IDEA and Android Studio release.
Download and install one of these IDEs to start using Kotlin.
Create
your
powerful
application
with
Kotlin
Backend app
Here is how you can take the first steps in developing Kotlin server-side applications.
To start from scratch, create a basic JVM application with the IntelliJ IDEA project wizard.
If you prefer more robust examples, choose one of the frameworks below and create a project:
Spring Ktor
A mature family of frameworks with an established ecosystem that is used A lightweight framework for those who value freedom in making
by millions of developers worldwide. architectural decisions.
Create a RESTful web service with Spring Boot. Create HTTP APIs with Ktor.
Build web applications with Spring Boot and Kotlin. Create a WebSocket chat with Ktor.
Use Spring Boot with Kotlin and RSocket. Create an interactive website with Ktor.
2. Use Kotlin and third-party libraries in your application. Learn more about adding library and tool dependencies to your project.
The Kotlin standard library offers a lot of useful things such as collections or coroutines.
Take a look at the following third-party frameworks, libs and tools for Kotlin.
54
How to write your first unit test.
Slack: get an invite and join the #getting-started, #server, #spring, or #ktor channels.
5. Follow Kotlin on Twitter, Reddit, and Youtube, and don't miss any important ecosystem updates.
Here you'll learn how to develop and improve your cross-platform mobile application usingKotlin Multiplatform Mobile.
To start from scratch, create a basic cross-platform mobile application with the project wizard.
If you have an existing Android application and want to make it cross-platform, complete theMake your Android application work on iOStutorial.
If you prefer real-life examples, clone and play with an existing project, for example the networking and data storage project from thehands-on
tutorial or any sample project.
3. Use a wide set of multiplatform libraries to implement the required business logic only once in the shared module. Learn more aboutadding
dependencies.
Library Details
Ktor Docs.
DateTime Docs.
Learn how Kotlin Multiplatform is used at Netflix, VMware, Yandex, and many other companies.
55
Slack: get an invite and join the #getting-started and #multiplatform channels.
6. Follow Kotlin on Twitter, Reddit, and Youtube, and don't miss any important ecosystem updates.
Frontend web
app
Kotlin provides an ability to transpile your Kotlin code, the Kotlin standard library, and any compatible dependencies to JavaScript.
Here you'll learn how to develop and improve your frontend web application usingKotlin/JS.
To start from scratch, create a basic browser application with the IntelliJ IDEA project wizard.
If you prefer more robust examples, complete the Build a web application with React and Kotlin/JS tutorial. It includes a sample project that can
serve as a good starting point for your own projects, and contains useful snippets and templates.
Check out the list of Kotlin/JS samples for more ideas on how to use Kotlin/JS.
Library Details
kotlinx.browser The Kotlin library for accessing browser-specific functionality, including typical top-level objects such as document and
window.
kotlinx.html The Kotlin library for generating DOM elements using statically-typed HTML builders.
fritz2 A third-party lightweight, high-performance, independent library for building reactive web apps in Kotlin that are heavily
dependent on coroutines and flows.
Doodle A third-party vector-based UI framework that uses browser's capabilities to draw user interfaces.
Compose for Web, a part The JetBrains framework that brings Google's Jetpack Compose UI toolkit to the browser.
of Compose Multiplatform
kotlin-wrappers Provide convenient abstractions and deep integrations for one of the most popular JavaScript frameworks. Kotlin
wrappers also provide support for a number of adjacent technologies like react-redux, react-router, or styled-components.
56
Using dependencies from npm.
Slack: get an invite and join the #getting-started and #javascript channels.
5. Follow Kotlin on Twitter, Reddit, and Youtube, and don't miss any important ecosystem updates.
Android app
If you want to start using Kotlin for Android development, readGoogle's recommendation for getting started with Kotlin on Android.
If you're new to Android and want to learn to create applications with Kotlin, check outthis Udacity course.
Follow Kotlin on Twitter, Reddit, and Youtube, and don't miss any important ecosystem updates.
Multiplatform library
Support for multiplatform programming is one of Kotlin's key benefits. It reduces time spent writing and maintaining the same code for different platforms
while retaining the flexibility and benefits of native programming.
Complete the Create and publish a multiplatform library tutorial. It shows how to create a multiplatform library for JVM, JS, and Native platforms, test
it and publish to a local Maven repository.
2. Use libraries in your application. Learn more about adding dependencies on libraries.
Library Details
Coroutines Docs.
DateTime Docs.
57
Slack: get an invite and join the #getting-started and #multiplatform channels.
5. Follow Kotlin on Twitter, Reddit, and Youtube, and don't miss any important ecosystem updates.
Is
anything
missing?
If anything is missing or seems confusing on this page, please share your feedback.
Kotlin
Multiplatform
Multiplatform projects are in Alpha. Language features and tooling may change in future Kotlin versions.
Support for multiplatform programming is one of Kotlin's key benefits. It reduces time spent writing and maintaining the same code for
different platforms while retaining the flexibility and benefits of native programming.
Kotlin
Multiplatform
use
cases
Android
and
iOS
applications
Sharing code between mobile platforms is one of the major Kotlin Multiplatform use cases. With Kotlin Multiplatform Mobile, you can build
cross-platform mobile applications and share common code between Android and iOS, such as business logic, connectivity, and more.
Check out the Get started with Kotlin Multiplatform Mobile section and Kotlin Multiplatform Hands-on: Networking and Data Storage,
where you will create an application for Android and iOS that includes a module with shared code for both platforms.
Full-stack
web
applications
Another scenario when code sharing may bring benefits is a connected application where the logic can be reused on both the server and
the client side running in the browser. This is covered by Kotlin Multiplatform as well.
See Build a full-stack web app with Kotlin Multiplatform tutorial, where you will create a connected application consisting of a server part,
using Kotlin/JVM and a web client, using Kotlin/JS.
Multiplatform
libraries
Kotlin Multiplatform is also useful for library authors. You can create a multiplatform library with common code and its platform-specific
implementations for JVM, JS, and Native platforms. Once published, a multiplatform library can be used in other cross-platform projects
as a dependency.
See the Create and publish a multiplatform library tutorial, where you will create a multiplatform library, test it, and publish it to Maven.
Common
code
for
mobile
and
web
applications
One more popular case for using Kotlin Multiplatform is sharing the same code across Android, iOS, and web apps. It reduces the amount
58
of business logic coded by frontend developers and helps implement products more efficiently, decreasing the coding and testing efforts.
See the RSS Reader sample project — a cross-platform application for iOS and Android with desktop and web clients implemented as
experimental features.
How
Kotlin
Multiplatform
works
Kotlin Multiplatform
Common Kotlin includes the language, core libraries, and basic tools. Code written in common Kotlin works everywhere on all
platforms.
With Kotlin Multiplatform libraries, you can reuse the multiplatform logic in common and platform-specific code. Common code can rely
59
on a set of libraries that cover everyday tasks such as HTTP, serialization, and managing coroutines.
To interop with platforms, use platform-specific versions of Kotlin. Platform-specific versions of Kotlin (Kotlin/JVM, Kotlin/JS,
Kotlin/Native) include extensions to the Kotlin language, and platform-specific libraries and tools.
Through these platforms you can access the platform native code (JVM, JS, and Native) and leverage all native capabilities.
Code
sharing
between
platforms
With Kotlin Multiplatform, spend less time on writing and maintaining the same code for different platforms – just share it using the
mechanisms Kotlin provides:
Share code among all platforms used in your project. Use it for sharing the common business logic that applies to all platforms.
Share code among some platforms included in your project but not all. Do this when you can reuse much of the code in similar
platforms:
If you need to access platform-specific APIs from the shared code, use the Kotlin mechanism of expected and actual declarations.
Get
started
Look through our examples and tutorials if you want to create applications or libraries targeting JVM, JavaScript, and other platforms
Start with the Get started with Kotlin Multiplatform Mobile if you want to create iOS and Android applications with shared code
Sample
projects
Look through cross-platform application samples to understand how Kotlin Multiplatform works:
KotlinConf app
60
KotlinConf Spinner app
Kotlin
for
server
side
Kotlin is a great fit for developing server-side applications. It allows you to write concise and expressive code while maintaining full
compatibility with existing Java-based technology stacks, all with a smooth learning curve:
Expressiveness: Kotlin's innovative language features, such as its support for type-safe builders and delegated properties, help build
powerful and easy-to-use abstractions.
Scalability: Kotlin's support for coroutines helps build server-side applications that scale to massive numbers of clients with modest
hardware requirements.
Interoperability: Kotlin is fully compatible with all Java-based frameworks, so you can use your familiar technology stack while reaping
the benefits of a more modern language.
Migration: Kotlin supports gradual migration of large codebases from Java to Kotlin. You can start writing new code in Kotlin while
keeping older parts of your system in Java.
Tooling: In addition to great IDE support in general, Kotlin offers framework-specific tooling (for example, for Spring) in the plugin for
IntelliJ IDEA Ultimate.
Learning Curve: For a Java developer, getting started with Kotlin is very easy. The automated Java-to-Kotlin converter included in the
Kotlin plugin helps with the first steps. Kotlin Koans can guide you through the key features of the language with a series of interactive
exercises.
Frameworks
for
server-side
development
with
Kotlin
Spring makes use of Kotlin's language features to offer more concise APIs, starting with version 5.0. The online project generator
allows you to quickly generate a new project in Kotlin.
Vert.x, a framework for building reactive Web applications on the JVM, offers dedicated support for Kotlin, including full documentation.
Ktor is a framework built by JetBrains for creating Web applications in Kotlin, making use of coroutines for high scalability and offering
an easy-to-use and idiomatic API.
kotlinx.html is a DSL that can be used to build HTML in Web applications. It serves as an alternative to traditional templating systems
such as JSP and FreeMarker.
Micronaut is a modern JVM-based full-stack framework for building modular, easily testable microservices and serverless applications.
It comes with a lot of useful built-in features.
http4k is the functional toolkit with a tiny footprint for Kotlin HTTP applications, written in pure Kotlin. The library is based on the "Your
Server as a Function" paper from Twitter and represents modeling both HTTP servers and clients as simple Kotlin functions that can be
composed together.
Javalin is a very lightweight web framework for Kotlin and Java which supports WebSockets, HTTP2, and async requests.
The available options for persistence include direct JDBC access, JPA, and using NoSQL databases through their Java drivers. For
JPA, the kotlin-jpa compiler plugin adapts Kotlin-compiled classes to the requirements of the framework.
61
Deploying
Kotlin
server-side
applications
Kotlin applications can be deployed into any host that supports Java Web applications, including Amazon Web Services, Google Cloud
Platform, and more.
To deploy Kotlin applications on Heroku, you can follow the official Heroku tutorial.
AWS Labs provides a sample project showing the use of Kotlin for writing AWS Lambda functions.
Google Cloud Platform offers a series of tutorials for deploying Kotlin applications to GCP, both for Ktor and App Engine and Spring and
App engine. In addition, there is an interactive code lab for deploying a Kotlin Spring application.
Products
that
use
Kotlin
on
the
server
side
Corda is an open-source distributed ledger platform that is supported by major banks and built entirely in Kotlin.
JetBrains Account, the system responsible for the entire license sales and validation process at JetBrains, is written in 100% Kotlin and
has been running in production since 2015 with no major issues.
Next
steps
For a more in-depth introduction to the language, check out the Kotlin documentation on this site and Kotlin Koans.
Watch a webinar "Micronaut for microservices with Kotlin" and explore a detailed guide showing how you can use Kotlin extension
functions in the Micronaut framework.
http4k provides the CLI to generate fully formed projects, and a starter repo to generate an entire CD pipeline using GitHub, Travis, and
Heroku with a single bash command.
Want to migrate from Java to Kotlin? Learn how to perform typical tasks with strings in Java and Kotlin.
Kotlin
for
Android
Android mobile development has been Kotlin-first since Google I/O in 2019.
Less code combined with greater readability. Spend less time writing your code and working to understand the code of others.
Mature language and environment. Since its creation in 2011, Kotlin has developed continuously, not only as a language but as a
whole ecosystem with robust tooling. Now it's seamlessly integrated in Android Studio and is actively used by many companies for
developing Android applications.
Kotlin support in Android Jetpack and other libraries. KTX extensions add Kotlin language features, such as coroutines, extension
functions, lambdas, and named parameters, to existing Android libraries.
Interoperability with Java. You can use Kotlin along with the Java programming language in your applications without needing to
migrate all your code to Kotlin.
Support for multiplatform development. You can use Kotlin for developing not only Android but also iOS, backend, and web
applications. Enjoy the benefits of sharing the common code among the platforms.
Code safety. Less code and better readability lead to fewer errors. The Kotlin compiler detects these remaining errors, making the code
62
safe.
Easy learning. Kotlin is very easy to learn, especially for Java developers.
Big community. Kotlin has great support and many contributions from the community, which is growing all over the world. According to
Google, over 60% of the top 1000 apps on the Play Store use Kotlin.
Many startups and Fortune 500 companies have already developed Android applications using Kotlin – see the list at the Google website
for Kotlin developers.
If you want to start using Kotlin for Android development, read Google's recommendation for getting started with Kotlin on Android.
If you're new to Android and want to learn to create applications with Kotlin, check out this Udacity course.
Kotlin
for
JavaScript
Kotlin/JS provides the ability to transpile your Kotlin code, the Kotlin standard library, and any compatible dependencies to JavaScript. The
current implementation of Kotlin/JS targets ES5.
The recommended way to use Kotlin/JS is via the kotlin.js and kotlin.multiplatform Gradle plugins. They let you easily set up and control
Kotlin projects targeting JavaScript in one place. This includes essential functionality such as controlling the bundling of your application,
adding JavaScript dependencies directly from npm, and more. To get an overview of the available options, check out the Kotlin/JS project
setup documentation.
Use
cases
for
Kotlin/JS
There are numerous ways to use Kotlin/JS. Here is a non-exhaustive list of scenarios in which you can use Kotlin/JS:
Kotlin/JS allows you to leverage powerful browser and web APIs in a type-safe fashion. Create, modify, and interact with the
elements in the Document Object Model (DOM), use Kotlin code to control the rendering of canvas or WebGL components, and
enjoy access to many more features that modern browsers support.
Write full, type-safe React applications with Kotlin/JS using the kotlin-wrappers provided by JetBrains, which provide convenient
abstractions and deep integrations for React and other popular JavaScript frameworks. kotlin-wrappers also provides support for a
select number of adjacent technologies, like react-redux, react-router, and styled-components. Interoperability with the JavaScript
ecosystem means that you can also use third-party React components and component libraries.
Use the Kotlin/JS frameworks, which take full advantage of Kotlin concepts and its expressive power and conciseness.
The Node.js target provided by Kotlin/JS enables you to create applications that run on a server or are executed on serverless
infrastructure. This gives you all the advantages of executing in a JavaScript runtime, such as faster startup and a reduced memory
footprint. With kotlinx-nodejs, you have typesafe access to the Node.js API directly from your Kotlin code.
Use Kotlin's multiplatform projects to share code with other Kotlin targets
All the functionality of Kotlin/JS can also be accessed when using the Kotlin multiplatform Gradle plugin.
If your backend is written in Kotlin, you can share common code such as data models or validation logic with a frontend written in
Kotlin/JS, which allows you to write and maintain full-stack web applications.
You can also share business logic between your web interface and mobile apps for Android and iOS, and avoid duplicating
commonly used functionality, like providing abstractions around REST API endpoints, user authentication, or your domain models.
63
Create libraries for use with JavaScript and TypeScript
You don't have to write your whole application in Kotlin/JS – instead, you can generate libraries from your Kotlin code that can be
consumed as modules from any code base written in JavaScript or TypeScript, regardless of the other frameworks or technologies
you use. This approach of creating hybrid applications allows you to leverage the competencies that you and your team might
already have around web development while helping you reduce the amount of duplicated work, making it easier to keep your web
target consistent with other targets of your application.
Of course, this is not a complete list of all the ways you can use Kotlin/JS to your advantage, but merely some cherry-picked use cases.
We invite you to experiment with different combinations and find out what works best for your project.
Whatever your specific use case, Kotlin/JS projects can use compatible libraries from the Kotlin ecosystem, as well as third-party libraries
from the JavaScript and TypeScript ecosystems. To use the latter from Kotlin code, you can either provide your own typesafe wrappers,
use community-maintained wrappers, or let Dukat automatically generate Kotlin declarations for you. Using the Kotlin/JS-exclusive
dynamic type allows you to loosen the constraints of Kotlin's type system and skip creating detailed library wrappers, though this comes
at the expense of type safety.
Kotlin/JS is also compatible with the most common module systems: UMD, CommonJS, and AMD. The ability to produce and consume
modules means that you can interact with the JavaScript ecosystem in a structured manner.
Kotlin/JS
frameworks
Modern web development benefits significantly from frameworks that simplify building web applications. Here are a few examples of
popular web frameworks for Kotlin/JS written by different authors:
KVision
KVision is an object-oriented web framework that makes it possible to write applications in Kotlin/JS with ready-to-use components that
can be used as building blocks for your application's user interface. You can use both reactive and imperative programming models to
build your frontend, use connectors for Ktor, Spring Boot, and other frameworks to integrate it with your server-side applications, and
share code using Kotlin Multiplatform.
For updates and discussions about the framework, join the #kvision and #javascript channels in the Kotlin Slack.
fritz2
fritz2 is a standalone framework for building reactive web user interfaces. It provides its own type-safe DSL for building and rendering
HTML elements, and it makes use of Kotlin's coroutines and flows to express components and their data bindings. It provides state
management, validation, routing, and more out of the box, and integrates with Kotlin Multiplatform projects.
For updates and discussions about the framework, join the #fritz2 and #javascript channels in the Kotlin Slack.
Doodle
Doodle is a vector-based UI framework for Kotlin/JS. Doodle applications use the browser's graphics capabilities to draw user interfaces
instead of relying on DOM, CSS, or Javascript. By using this approach, Doodle gives you precise control over the rendering of arbitrary UI
elements, vector shapes, gradients, and custom visualizations.
64
For updates and discussions about the framework, join the #doodle and #javascript channels in the Kotlin Slack.
Compose
for
Web
Compose for Web, a part of Compose Multiplatform, brings Google's Jetpack Compose UI toolkit to your browser. It allows you to build
reactive web user interfaces using the concepts introduced by Jetpack Compose. It provides a DOM API to describe your website, as well
as an experimental set of multiplatform layout primitives. Compose for Web also gives you the option to share parts of your UI code and
logic across Android, desktop, and the web.
You can find more information about Compose Multiplatform on its landing page.
Join the #compose-web channel on the Kotlin Slack to discuss Compose for Web, or #compose for general Compose Multiplatform
discussions.
Kotlin/JS,
Today
and
Tomorrow
In this video, Kotlin Developer Advocate Sebastian Aigner explains the main Kotlin/JS benefits, shares some tips and use cases, and talks
about the plans and upcoming features for Kotlin/JS.
Gif
Get
started
with
Kotlin/JS
If you're new to Kotlin, a good first step is to familiarize yourself with the basic syntax of the language.
To start using Kotlin for JavaScript, please refer to Set up a Kotlin/JS project. You can also complete a tutorial to work through or check
out the list of Kotlin/JS sample projects for inspiration. They contain useful snippets and patterns and can serve as nice jump-off points for
your own projects.
Tutorials
for
Kotlin/JS
Build a web application with React and Kotlin/JS — tutorial guides you through the process of building a simple web application using
the React framework, shows how a type-safe Kotlin DSL for HTML makes it easy to build reactive DOM elements, and illustrates how
to use third-party React components and obtain information from APIs, all while writing the whole application logic in pure Kotlin/JS.
65
Build a full-stack web app with Kotlin Multiplatform teaches the concepts behind building an application that targets Kotlin/JVM and
Kotlin/JS by building a client-server application that makes use of shared code, serialization, and other multiplatform paradigms. It also
provides a brief introduction to working with Ktor both as a server- and client-side framework.
Sample
projects
for
Kotlin/JS
Full-stack Spring collaborative to-do list shows how to create a to-do list for collaborative work using kotlin-multiplatform with JS and
JVM targets, Spring for the backend, Kotlin/JS with React for the frontend, and RSocket.
Kotlin/JS and React Redux to-do list implements the React Redux to-do list using JS libraries (react, react-dom, react-router, redux,
and react-redux) from npm and Webpack to bundle, minify, and run the project.
Full-stack demo application guides you through the process of building an app with a feed containing user-generated posts and
comments. All data is stubbed by the fakeJSON and JSON Placeholder services.
New
Kotlin/JS
IR
compiler
The new Kotlin/JS IR compiler (currently with Beta stability) comes with a number of improvements over the current default compiler. For
example, it reduces the size of generated executables via dead code elimination and provides smoother interoperability with the
JavaScript ecosystem and its tooling. By generating TypeScript declaration files (d.ts) from Kotlin code, the new compiler makes it easier
to create "hybrid" applications that mix TypeScript and Kotlin code and to leverage code-sharing functionality using Kotlin Multiplatform.
To learn more about the available features in the new Kotlin/JS IR compiler and how to try it for your project, visit the Kotlin/JS IR compiler
documentation page and the migration guide.
Join
the
Kotlin/JS
community
You can also join the #javascript channel in the official Kotlin Slack to chat with the community and the team.
Kotlin
Native
Kotlin/Native is a technology for compiling Kotlin code to native binaries which can run without a virtual machine. Kotlin/Native includes an
LLVM-based backend for the Kotlin compiler and a native implementation of the Kotlin standard library.
Why
Kotlin/Native?
Kotlin/Native is primarily designed to allow compilation for platforms on which virtual machines are not desirable or possible, such as
embedded devices or iOS. It is ideal for situations when a developer needs to produce a self-contained program that does not require an
additional runtime or virtual machine.
Target
platforms
Kotlin/Native supports the following platforms:
macOS
66
Linux
Windows (MinGW)
Android NDK
To compile Apple targets, macOS, iOS, tvOS, and watchOS, you need Xcode and its command-line tools installed.
Interoperability
Kotlin/Native supports two-way interoperability with native programming languages for different operating systems. The compiler creates:
It is easy to include compiled Kotlin code in existing projects written in C, C++, Swift, Objective-C, and other languages. It is also easy to
use existing native code, static or dynamic C libraries, Swift/Objective-C frameworks, graphical engines, and anything else directly from
Kotlin/Native.
Kotlin/Native libraries help share Kotlin code between projects. POSIX, gzip, OpenGL, Metal, Foundation, and many other popular libraries
and Apple frameworks are pre-imported and included as Kotlin/Native libraries in the compiler package.
Sharing
code
between
platforms
Multiplatform projects allow sharing common Kotlin code between multiple platforms, including Android, iOS, JVM, JavaScript, and native.
Multiplatform libraries provide required APIs for common Kotlin code and help develop shared parts of a project in Kotlin in one place and
share it with some or all target platforms.
You can use Kotlin Multiplatform Mobile to create multiplatform mobile applications with code shared between Android and iOS.
How
to
get
started
Tutorials
and
documentation
New to Kotlin? Take a look at Getting started with Kotlin.
Recommended documentation:
Multiplatform documentation
67
C interop
Swift/Objective-C interop
Recommended tutorials:
Kotlin
for
data
science
From building data pipelines to productionizing machine learning models, Kotlin can be a great choice for working with data:
Static typing and null safety help create reliable, maintainable code that is easy to troubleshoot.
Being a JVM language, Kotlin gives you great performance and an ability to leverage an entire ecosystem of tried and true Java
libraries.
Interactive
editors
Notebooks such as Jupyter Notebook, Datalore, and Apache Zeppelin provide convenient tools for data visualization and exploratory
research. Kotlin integrates with these tools to help you explore data, share your findings with colleagues, or build up your data science and
machine learning skills.
Jupyter
Kotlin
kernel
The Jupyter Notebook is an open-source web application that allows you to create and share documents (aka "notebooks") that can
contain code, visualizations, and Markdown text. Kotlin-jupyter is an open source project that brings Kotlin support to Jupyter Notebook.
68
Kotlin in Jupyter notebook
Check out Kotlin kernel's GitHub repo for installation instructions, documentation, and examples.
Kotlin
Notebooks
in
Datalore
With Datalore, you can use Kotlin in the browser straight out of the box, no installation required. You can also collaborate on Kotlin
notebooks in real time, get smart coding assistance when writing code, and share results as interactive or static reports. Check out a
sample report.
69
Kotlin in Datalore
Zeppelin
Kotlin
interpreter
Apache Zeppelin is a popular web-based solution for interactive data analytics. It provides strong support for the Apache Spark cluster
computing system, which is particularly useful for data engineering. Starting from version 0.9.0, Apache Zeppelin comes with bundled
Kotlin interpreter.
Libraries
70
The ecosystem of libraries for data-related tasks created by the Kotlin community is rapidly expanding. Here are some libraries that you
may find useful:
Kotlin
libraries
Multik: multidimensional arrays in Kotlin. The library provides Kotlin-idiomatic, type- and dimension-safe API for mathematical
operations over multidimensional arrays. Multik offers swappable JVM and native computational engines, and a combination of the two
for optimal performance.
KotlinDL is a high-level Deep Learning API written in Kotlin and inspired by Keras. It offers simple APIs for training deep learning
models from scratch, importing existing Keras models for inference, and leveraging transfer learning for tweaking existing pre-trained
models to your tasks.
Kotlin DataFrame is a library for structured data processing. It aims to reconcile Kotlin's static typing with the dynamic nature of data
by utilizing both the full power of the Kotlin language and the opportunities provided by intermittent code execution in Jupyter
notebooks and REPLs.
Kotlin for Apache Spark adds a missing layer of compatibility between Kotlin and Apache Spark. It allows Kotlin developers to use
familiar language features such as data classes, and lambda expressions as simple expressions in curly braces or method references.
kotlin-statistics is a library providing extension functions for exploratory and production statistics. It supports basic numeric
list/sequence/array functions (from sum to skewness), slicing operators (such as countBy, simpleRegressionBy), binning operations,
discrete PDF sampling, naive bayes classifier, clustering, linear regression, and much more.
kmath is an experimental library that was intially inspired by NumPy but evolved to more flexible abstractions. It implements
mathematical operations combined in algebraic structures over Kotlin types, defines APIs for linear structures, expressions, histograms,
streaming operations, provides interchangeable wrappers over existing Java and Kotlin libraries including ND4J, Commons Math,
Multik, and others.
krangl is a library inspired by R's dplyr and Python's pandas. This library provides functionality for data manipulation using a functional-
style API; it also includes functions for filtering, transforming, aggregating, and reshaping tabular data.
lets-plot is a plotting library for statistical data written in Kotlin. Lets-Plot is multiplatform and can be used not only with JVM, but also
with JS and Python.
kravis is another library for the visualization of tabular data inspired by R's ggplot.
londogard-nlp-toolkit is a library that provides utilities when working with natural language processing such as word/subword/sentence
embeddings, word-frequencies, stopwords, stemming, and much more.
Java
libraries
Since Kotlin provides first-class interop with Java, you can also use Java libraries for data science in your Kotlin code. Here are some
examples of such libraries:
Smile - a comprehensive machine learning, natural language processing, linear algebra, graph, interpolation, and visualization system.
Besides Java API, Smile also provides a functional Kotlin API along with Scala and Clojure API.
Smile-NLP-kt - a Kotlin rewrite of the Scala implicits for the natural language processing part of Smile in the format of extension
functions and interfaces.
71
Apache Commons Math - a general math, statistics, and machine learning library for Java
Apache OpenNLP - a machine learning based toolkit for the processing of natural language text
If this list doesn't cover your needs, you can find more options in the Kotlin Machine Learning Demos GitHub repository with showcases
from Thomas Nield.
Kotlin
for
competitive
programming
This tutorial is designed both for competitive programmers that did not use Kotlin before and for Kotlin developers that did not participate
in any competitive programming events before. It assumes the corresponding programming skills.
Competitive programming is a mind sport where contestants write programs to solve precisely specified algorithmic problems within strict
constraints. Problems can range from simple ones that can be solved by any software developer and require little code to get a correct
solution, to complex ones that require knowledge of special algorithms, data structures, and a lot of practice. While not being specifically
designed for competitive programming, Kotlin incidentally fits well in this domain, reducing the typical amount of boilerplate that a
programmer needs to write and read while working with the code almost to the level offered by dynamically-typed scripting languages,
while having tooling and performance of a statically-typed language.
See Get started with Kotlin/JVM on how to set up development environment for Kotlin. In competitive programming, a single project is
usually created and each problem's solution is written in a single source file.
Simple
example:
Reachable
Numbers
problem
Let's take a look at a concrete example.
Codeforces Round 555 was held on April 26th for 3rd Division, which means it had problems fit for any developer to try. You can use this
link to read the problems. The simplest problem in the set is the Problem A: Reachable Numbers. It asks to implement a straightforward
algorithm described in the problem statement.
We'd start solving it by creating a Kotlin source file with an arbitrary name. A.kt will do well. First, you need to implement a function
specified in the problem statement as:
Let's denote a function f(x) in such a way: we add 1 to x, then, while there is at least one trailing zero in the resulting number, we remove
that zero.
Kotlin is a pragmatic and unopinionated language, supporting both imperative and function programming styles without pushing the
developer towards either one. You can implement the function f in functional style, using such Kotlin features as tail recursion:
72
if (x % 10 == 0) removeZeroes(x / 10) else x
fun f(x: Int) = removeZeroes(x + 1)
Alternatively, you can write an imperative implementation of the function f using the traditional while loop and mutable variables that are
denoted in Kotlin with var:
Types in Kotlin are optional in many places due to pervasive use of type-inference, but every declaration still has a well-defined static type
that is known at compilation.
Now, all is left is to write the main function that reads the input and implements the rest of the algorithm that the problem statement asks
for — to compute the number of different integers that are produced while repeatedly applying function f to the initial number n that is
given in the standard input.
By default, Kotlin runs on JVM and gives direct access to a rich and efficient collections library with general-purpose collections and data-
structures like dynamically-sized arrays (ArrayList), hash-based maps and sets (HashMap/HashSet), tree-based ordered maps and sets
(TreeMap/TreeSet). Using a hash-set of integers to track values that were already reached while applying function f, the straightforward
imperative version of a solution to the problem can be written as shown below:
fun main() {
var n = readln().toInt() // read integer from the input
val reached = HashSet<Int>() // a mutable hash set
while (reached.add(n)) n = f(n) // iterate function f
println(reached.size) // print answer to the output
}
There is no need to handle the case of misformatted input in competitive programming. An input format is always precisely specified in competitive
programming, and the actual input cannot deviate from the input specification in the problem statement. That's why you can use Kotlin's readln() function. It
asserts that the input string is present and throws an exception otherwise. Likewise, the String.toInt() function throws an exception if the input string is not
an integer.
Earlier versions
fun main() {
var n = readLine()!!.toInt() // read integer from the input
val reached = HashSet<Int>() // a mutable hash set
while (reached.add(n)) n = f(n) // iterate function f
println(reached.size) // print answer to the output
}
Note the use of Kotlin's null-assertion operator !! after the readLine() function call. Kotlin's readLine() function is defined to return a nullable type String? and
returns null on the end of the input, which explicitly forces the developer to handle the case of missing input.
There is no need to handle the case of misformatted input in competitive programming. In competitive programming, an input format is always precisely
specified and the actual input cannot deviate from the input specification in the problem statement. That's what the null-assertion operator !! essentially
does — it asserts that the input string is present and throws an exception otherwise. Likewise, the String.toInt().
73
All online competitive programming events allow the use of pre-written code, so you can define your own library of utility functions that are
geared towards competitive programming to make your actual solution code somewhat easier to read and write. You would then use this
code as a template for your solutions. For example, you can define the following helper functions for reading inputs in competitive
programming:
Earlier versions
Note the use of private visibility modifier here. While the concept of visibility modifier is not relevant for competitive programming at all, it
allows you to place multiple solution files based on the same template without getting an error for conflicting public declarations in the
same package.
Functional
operators
example:
Long
Number
problem
For more complicated problems, Kotlin's extensive library of functional operations on collections comes in handy to minimize the
boilerplate and turn the code into a linear top-to-bottom and left-to-right fluent data transformation pipeline. For example, the Problem B:
Long Number problem takes a simple greedy algorithm to implement and it can be written using this style without a single mutable
variable:
fun main() {
// read input
val n = readln().toInt()
val s = readln()
val fl = readln().split(" ").map { it.toInt() }
// define local function f
fun f(c: Char) = '0' + fl[c - '1']
// greedily find first and last indices
val i = s.indexOfFirst { c -> f(c) > c }
.takeIf { it >= 0 } ?: s.length
val j = s.withIndex().indexOfFirst { (j, c) -> j > i && f(c) < c }
.takeIf { it >= 0 } ?: s.length
// compose and write the answer
val ans =
s.substring(0, i) +
s.substring(i, j).map { c -> f(c) }.joinToString("") +
s.substring(j)
println(ans)
}
Earlier versions
fun main() {
// read input
74
val n = readLine()!!.toInt()
val s = readLine()!!
val fl = readLine()!!.split(" ").map { it.toInt() }
// define local function f
fun f(c: Char) = '0' + fl[c - '1']
// greedily find first and last indices
val i = s.indexOfFirst { c -> f(c) > c }
.takeIf { it >= 0 } ?: s.length
val j = s.withIndex().indexOfFirst { (j, c) -> j > i && f(c) < c }
.takeIf { it >= 0 } ?: s.length
// compose and write the answer
val ans =
s.substring(0, i) +
s.substring(i, j).map { c -> f(c) }.joinToString("") +
s.substring(j)
println(ans)
}
In this dense code, in addition to collection transformations, you can see such handy Kotlin features as local functions and the elvis
operator ?: that allow to express idioms like "take the value if it is positive or else use length" with a concise and readable expressions like
.takeIf { it >= 0 } ?: s.length, yet it is perfectly fine with Kotlin to create additional mutable variables and express the same code in
imperative style, too.
To make reading the input in competitive programming tasks like this more concise, you can have the following list of helper input-reading
functions:
Earlier versions
With these helpers, the part of code for reading input becomes simpler, closely following the input specification in the problem statement
line by line:
// read input
val n = readInt()
val s = readln()
val fl = readInts()
Earlier versions
// read input
val n = readInt()
val s = readLn()
val fl = readInts()
75
Note that in competitive programming it is customary to give variables shorter names than it is typical in industrial programming practice,
since the code is to be written just once and not supported thereafter. However, these names are usually still mnemonic — a for arrays, i, j,
and others for indices, r, and c for row and column numbers in tables, x and y for coordinates, and so on. It is easier to keep the same
names for input data as it is given in the problem statement. However, more complex problems require more code which leads to using
longer self-explanatory variable and function names.
More
tips
and
tricks
Competitive programming problems often have input like this:
In Kotlin this line can be concisely parsed with the following statement using destructuring declaration from a list of integers:
It might be temping to use JVM's java.util.Scanner class to parse less structured input formats. Kotlin is designed to interoperate well with
JVM libraries, so that their use feels quite natural in Kotlin. However, beware that java.util.Scanner is extremely slow. So slow, in fact, that
parsing 105 or more integers with it might not fit into a typical 2 second time-limit, which a simple Kotlin's split(" ").map { it.toInt() } would
handle.
Writing output in Kotlin is usually straightforward with println(...) calls and using Kotlin's string templates. However, care must be taken
when output contains on order of 105 lines or more. Issuing so many println calls is too slow, since the output in Kotlin is automatically
flushed after each line. A faster way to write many lines from an array or a list is using joinToString() function with "\n" as the separator, like
this:
Learning
Kotlin
Kotlin is easy to learn, especially for those who already know Java. A short introduction to the basic syntax of Kotlin for software
developers can be found directly in the reference section of the website starting from basic syntax.
IDEA has built-in Java-to-Kotlin converter. It can be used by people familiar with Java to learn the corresponding Kotlin syntactic
constructions, but it is not perfect, and it is still worth familiarizing yourself with Kotlin and learning the Kotlin idioms.
A great resource to study Kotlin syntax and API of the Kotlin standard library are Kotlin Koans.
What's
new
in
Kotlin
1.7.20
Release date: September 29, 2022
The Kotlin 1.7.20 release is out! Here are some highlights from this release:
The new Kotlin K2 compiler supports all-open, SAM with receiver, Lombok, and other compiler plugins
We introduced the preview of the ..< operator for creating open-ended ranges
76
We introduced a new experimental feature for JVM: inline classes with a generic underlying type
You can also find a short overview of the changes in this video:
Gif
Support
for
Kotlin
K2
compiler
plugins
The Kotlin team continues to stabilize the K2 compiler. K2 is still in Alpha (as announced in the Kotlin 1.7.0 release), but it now supports
several compiler plugins. You can follow this YouTrack issue to get updates from the Kotlin team on the new compiler.
Starting with this 1.7.20 release, the Kotlin K2 compiler supports the following plugins:
all-open
no-arg
Lombok
AtomicFU
jvm-abi-gen
The Alpha version of the new K2 compiler only works with JVM projects. It doesn't support Kotlin/JS, Kotlin/Native, or other
multi-platform projects.
Learn more about the new compiler and its benefits in the following videos:
How
to
enable
the
Kotlin
K2
compiler
77
To enable the Kotlin K2 compiler and test it, use the following compiler option:
-Xuse-k2
You can check out the performance boost on your JVM projects and compare it with the results of the old compiler.
Leave
your
feedback
on
the
new
K2
compiler
We really appreciate your feedback in any form:
Provide your feedback directly to K2 developers in Kotlin Slack: get an invite and join the #k2-early-adopters channel.
Report any problems you faced with the new K2 compiler to our issue tracker.
Enable the Send usage statistics option to allow JetBrains collecting anonymous data about K2 usage.
Language
Kotlin 1.7.20 introduces preview versions for new language features, as well as puts restrictions on builder type inference:
Preview
of
the
..<
operator
for
creating
open-ended
ranges
The new operator is Experimental, and it has limited support in the IDE.
This release introduces the new ..< operator. Kotlin has the .. operator to express a range of values. The new ..< operator acts like the until
function and helps you define the open-ended range.
Gif
78
Watch video online.
Our research shows that this new operator does a better job at expressing open-ended ranges and making it clear that the upper bound is
not included.
when (value) {
in 0.0..<0.25 -> // first quarter
in 0.25..<0.5 -> // second quarter
in 0.5..<0.75 -> // third quarter
in 0.75..1.0 -> // last quarter <- note closed range here
}
The new API elements introduced to support the open-ended ranges of the standard types require an opt-in, as usual for an experimental
stdlib API: @OptIn(ExperimentalStdlibApi::class). Alternatively, you could use the -opt-in=kotlin.ExperimentalStdlibApi compiler option.
79
Read more about the new operator in this KEEP document.
Improved
string
representations
for
singletons
and
sealed
class
hierarchies
with
data
objects
Data objects are Experimental, and have limited support in the IDE at the moment.
This release introduces a new type of object declaration for you to use: data object. Data object behaves conceptually identical to a
regular object declaration but comes with a clean toString representation out of the box.
Gif
package org.example
object MyObject
data object MyDataObject
fun main() {
println(MyObject) // org.example.MyObject@1f32e575
println(MyDataObject) // MyDataObject
}
This makes data object declarations perfect for sealed class hierarchies, where you may use them alongside data class declarations. In
this snippet, declaring EndOfFile as a data object instead of a plain object means that it will get a pretty toString without the need to
override it manually, maintaining symmetry with the accompanying data class definitions:
fun main() {
println(ReadResult.Number(1)) // Number(value=1)
println(ReadResult.Text("Foo")) // Text(value=Foo)
println(ReadResult.EndOfFile) // EndOfFile
}
80
How to enable data objects
To use data object declarations in your code, enable the -language-version 1.8 compiler option. In a Gradle project, you can do so by
adding the following to your build.gradle(.kts):
Kotlin
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
// . . .
kotlinOptions.languageVersion = "1.8"
}
Groovy
compileKotlin {
// . . .
kotlinOptions.languageVersion = '1.8'
}
Read more about data objects, and share your feedback on their implementation in the respective KEEP document.
New
builder
type
inference
restrictions
Kotlin 1.7.20 places some major restrictions on the use of builder type inference that could affect your code. These restrictions apply to
code containing builder lambda functions, where it's impossible to derive the parameter without analyzing the lambda itself. The parameter
is used as an argument. Now, the compiler will always show an error for such code and ask you to specify the type explicitly.
This is a breaking change, but our research shows that these cases are very rare, and the restrictions shouldn't affect your code. If they
do, consider the following cases:
If your code contains an extension function with the same name that will be used during the builder inference, the compiler will show
you an error:
class Data {
fun doSmth() {} // 1
}
fun test() {
buildList {
this.add(Data())
this.get(0).doSmth() // Resolves to 2 and leads to error
}
}
class Data {
fun doSmth() {} // 1
}
fun test() {
buildList<Data> { // Type argument!
81
this.add(Data())
this.get(0).doSmth() // resolves to 1
}
}
Builder inference with multiple lambdas and the type arguments are not specified explicitly.
If there are two or more lambda blocks in builder inference, they affect the type. To prevent an error, the compiler requires you to
specify the type:
fun main() {
buildList(
first = { // this: MutableList<String>
add("")
},
second = { // this: MutableList<Int>
val i: Int = get(0)
println(i)
}
)
}
To fix the error, you should specify the type explicitly and fix the type mismatch:
fun main() {
buildList<Int>(
first = { // this: MutableList<Int>
add(0)
},
second = { // this: MutableList<Int>
val i: Int = get(0)
println(i)
}
)
}
If you haven't found your case mentioned above, file an issue to our team.
See this YouTrack issue for more information about this builder inference update.
Kotlin/JVM
Kotlin 1.7.20 introduces generic inline classes, adds more bytecode optimizations for delegated properties, and supports IR in the kapt
stub generating task, making it possible to use all the newest Kotlin features with kapt:
82
Generic
inline
classes
Generic inline classes is an Experimental feature. It may be dropped or changed at any time. Opt-in is required (see details
below), and you should use it only for evaluation purposes. We would appreciate your feedback on it in YouTrack.
Kotlin 1.7.20 allows the underlying type of JVM inline classes to be a type parameter. The compiler maps it to Any? or, generally, to the
upper bound of the type parameter.
Gif
@JvmInline
value class UserId<T>(val value: T)
The function accepts the inline class as a parameter. The parameter is mapped to the upper bound, not the type argument.
More
optimized
cases
of
delegated
properties
In Kotlin 1.6.0, we optimized the case of delegating to a property by omitting the $delegate field and generating immediate access to the
referenced property. In 1.7.20, we've implemented this optimization for more cases. The $delegate field will now be omitted if a delegate
is:
A named object:
object NamedObject {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String = ...
}
83
A final val property with a backing field and a default getter in the same module:
class A {
val s: String by impl
}
class A {
operator fun getValue(thisRef: Any?, property: KProperty<*>) ...
val s by this
}
Support
for
the
JVM
IR
backend
in
kapt
stub
generating
task
Support for the JVM IR backend in the kapt stub generating task is an Experimental feature. It may be changed at any time. Opt-
in is required (see details below), and you should use it only for evaluation purposes.
Before 1.7.20, the kapt stub generating task used the old backend, and repeatable annotations didn't work with kapt. With Kotlin 1.7.20,
we've added support for the JVM IR backend in the kapt stub generating task. This makes it possible to use all the newest Kotlin features
with kapt, including repeatable annotations.
To use the IR backend in kapt, add the following option to your gradle.properties file:
kapt.use.jvm.ir=true
Kotlin/Native
Kotlin 1.7.20 comes with the new Kotlin/Native memory manager enabled by default and gives you the option to customize the Info.plist
file:
The
new
Kotlin/Native
memory
manager
enabled
by
default
This release brings further stability and performance improvements to the new memory manager, allowing us to promote the new memory
manager to Beta.
The previous memory manager complicated writing concurrent and asynchronous code, including issues with implementing the
84
kotlinx.coroutines library. This blocked the adoption of Kotlin Multiplatform Mobile because concurrency limitations created problems with
sharing Kotlin code between iOS and Android platforms. The new memory manager finally paves the way to promote Kotlin Multiplatform
Mobile to Beta.
The new memory manager also supports the compiler cache that makes compilation times comparable to previous releases. For more on
the benefits of the new memory manager, see our original blog post for the preview version. You can find more technical details in the
documentation.
If you've already turned it on manually, you can remove the kotlin.native.binary.memoryModel=experimental option from your
gradle.properties or binaryOptions["memoryModel"] = "experimental" from the build.gradle(.kts) file.
If necessary, you can switch back to the legacy memory manager with the kotlin.native.binary.memoryModel=strict option in your
gradle.properties. However, compiler cache support is no longer available for the legacy memory manager, so compilation times might
worsen.
Freezing
In the new memory manager, freezing is deprecated. Don't use it unless you need your code to work with the legacy manager (where
freezing is still required). This may be helpful for library authors that need to maintain support for the legacy memory manager or
developers who want to have a fallback if they encounter issues with the new memory manager.
In such cases, you can temporarily support code for both new and legacy memory managers. To ignore deprecation warnings, do one of
the following:
This restriction was originally introduced in the legacy memory manager due to cases where the code dispatched a continuation to be
resumed on the original thread. If this thread didn't have a supported event loop, the task would never run, and the coroutine would never
be resumed.
In certain cases, this restriction is no longer required, but a check of all the necessary conditions can't be easily implemented. Because of
this, we decided to keep it in the new memory manager while introducing an option for you to disable it. For this, add the following option
to your gradle.properties:
kotlin.native.binary.objcExportSuspendFunctionLaunchThreadRestriction=none
Do not add this option if you use the native-mt version of kotlinx.coroutines or other libraries that have the same "dispatch to the
original thread" approach.
The Kotlin team is very grateful to Ahmed El-Helw for implementing this option.
85
Leave your feedback
This is a significant change to our ecosystem. We would appreciate your feedback to help make it even better.
Try the new memory manager on your projects and share feedback in our issue tracker, YouTrack.
Customizing
the
Info.plist
file
When producing a framework, the Kotlin/Native compiler generates the information property list file, Info.plist. Previously, it was
cumbersome to customize its contents. With Kotlin 1.7.20, you can directly set the following properties:
CFBundleIdentifier bundleId
CFBundleShortVersionString bundleShortVersionString
CFBundleVersion bundleVersion
To do that, use the corresponding binary option. Pass the -Xbinary=$option=$value compiler flag or set the binaryOption(option, value)
Gradle DSL for the necessary framework.
The Kotlin team is very grateful to Mads Ager for implementing this feature.
Kotlin/JS
Kotlin/JS has received some enhancements that improve the developer experience and boost performance:
Klib generation is faster in both incremental and clean builds, thanks to efficiency improvements for the loading of dependencies.
Incremental compilation for development binaries has been reworked, resulting in major improvements in clean build scenarios, faster
incremental builds, and stability fixes.
We've improved .d.ts generation for nested objects, sealed classes, and optional parameters in constructors.
Gradle
The updates for the Kotlin Gradle plugin are focused on compatibility with the new Gradle features and the latest Gradle versions.
Kotlin 1.7.20 contains changes to support Gradle 7.1. Deprecated methods and properties were removed or replaced, reducing the
number of deprecation warnings produced by the Kotlin Gradle plugin and unblocking future support for Gradle 8.0.
There are, however, some potentially breaking changes that may need your attention:
Target
configuration
org.jetbrains.kotlin.gradle.dsl.SingleTargetExtension now has a generic parameter, SingleTargetExtension<T : KotlinTarget>.
The kotlin.targets.fromPreset() convention has been deprecated. Instead, you can still use kotlin.targets { fromPreset() }, but we
recommend using more specialized ways to create targets.
86
Target accessors auto-generated by Gradle are no longer available inside the kotlin.targets { } block. Please use the
findByName("targetName") method instead.
Note that such accessors are still available in the case of kotlin.targets, for example, kotlin.targets.linuxX64.
Source
directories
configuration
The Kotlin Gradle plugin now adds Kotlin SourceDirectorySet as a kotlin extension to Java's SourceSet group. This makes it possible to
configure source directories in the build.gradle.kts file similarly to how they are configured in Java, Groovy, and Scala:
sourceSets {
main {
kotlin {
java.setSrcDirs(listOf("src/java"))
kotlin.setSrcDirs(listOf("src/kotlin"))
}
}
}
You no longer need to use a deprecated Gradle convention and specify the source directories for Kotlin.
Remember that you can also use the kotlin extension to access KotlinSourceSet:
kotlin {
sourceSets {
main {
// …
}
}
}
New
method
for
JVM
toolchain
configuration
This release provides the new jvmToolchain() method for enabling the JVM toolchain feature. If you don't need any additional configuration
fields, such as implementation or vendor, you can use this method from the Kotlin extension:
kotlin {
jvmToolchain(17)
}
This simplifies the Kotlin project setup process without any additional configuration. Before this release, you could specify the JDK version
only in the following way:
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
Standard
library
Kotlin 1.7.20 offers new extension functions for the java.nio.file.Path class, which allows you to walk through a file tree:
walk() lazily traverses the file tree rooted at the specified path.
87
fileVisitor() makes it possible to create a FileVisitor separately. FileVisitor defines actions on directories and files when traversing them.
visitFileTree(fileVisitor: FileVisitor, ...) consumes a ready FileVisitor and uses java.nio.file.Files.walkFileTree() under the hood.
visitFileTree(..., builderAction: FileVisitorBuilder.() -> Unit) creates a FileVisitor with the builderAction and calls the visitFileTree(fileVisitor,
...) function.
FileVisitResult, return type of FileVisitor, has the CONTINUE default value that continues the processing of the file.
The new extension functions for java.nio.file.Path are Experimental. They may be changed at any time. Opt-in is required (see
details below), and you should use them only for evaluation purposes.
Here are some things you can do with these new extension functions:
projectDirectory.visitFileTree(cleanVisitor)
projectDirectory.visitFileTree {
// Definition of the builderAction:
onPreVisitDirectory { directory, attributes ->
// Some logic on visiting directories
FileVisitResult.CONTINUE
}
Traverse a file tree rooted at the specified path with the walk() function:
@OptIn(kotlin.io.path.ExperimentalPathApi::class)
fun taverseFileTree() {
val cleanVisitor = fileVisitor {
onPreVisitDirectory { directory, _ ->
if (directory.name == "build") {
directory.toFile().deleteRecursively()
FileVisitResult.SKIP_SUBTREE
} else {
FileVisitResult.CONTINUE
}
88
}
rootDirectory.visitFileTree(cleanVisitor)
As is usual for an experimental API, the new extensions require an opt-in: @OptIn(kotlin.io.path.ExperimentalPathApi::class) or
@kotlin.io.path.ExperimentalPathApi. Alternatively, you can use a compiler option: -opt-in=kotlin.io.path.ExperimentalPathApi.
We would appreciate your feedback on the walk() function and the visit extension functions in YouTrack.
Documentation
updates
Since the previous release, the Kotlin documentation has received some notable changes:
Revamped
and
improved
pages
Basic types overview − learn about the basic types used in Kotlin: numbers, Booleans, characters, strings, arrays, and unsigned integer
numbers.
IDEs for Kotlin development − see the list of IDEs with official Kotlin support and tools that have community-supported plugins.
New
articles
in
the
Kotlin
Multiplatform
journal
Native and cross-platform app development: how to choose? − check out our overview and advantages of cross-platform app
development and the native approach.
89
The six best cross-platform app development frameworks − read about the key aspects to help you choose the right framework for
your cross-platform project.
New
and
updated
tutorials
Get started with Kotlin Multiplatform Mobile − learn about cross-platform mobile development with Kotlin and create an app that works
on both Android and iOS.
Build a full-stack web app with Kotlin Multiplatform − create an app using Kotlin throughout the whole stack, with a Kotlin/JVM server
part and a Kotlin/JS web client.
Build a web application with React and Kotlin/JS − create a browser app exploring Kotlin's DSLs and features of a typical React
program.
Changes
in
release
documentation
We no longer provide a list of recommended kotlinx libraries for each release. This list included only the versions recommended and tested
with Kotlin itself. It didn't take into account that some libraries depend on each other and require a special kotlinx version, which may differ
from the recommended Kotlin version.
We're working on finding a way to provide information on how libraries interrelate and depend on each other so that it will be clear which
kotlinx library version you should use when you upgrade the Kotlin version in your project.
Install
Kotlin
1.7.20
IntelliJ IDEA 2021.3, 2022.1, and 2022.2 automatically suggest updating the Kotlin plugin to 1.7.20.
For Android Studio Dolphin (213), Electric Eel (221), and Flamingo (222), the Kotlin plugin 1.7.20 will be delivered with upcoming
Android Studios updates.
The new command-line compiler is available for download on the GitHub release page.
Compatibility
guide
for
Kotlin
1.7.20
Although Kotlin 1.7.20 is an incremental release, there are still incompatible changes we had to make to limit spread of the issues
introduced in Kotlin 1.7.0.
Find the detailed list of such changes in the Compatibility guide for Kotlin 1.7.20.
What's
new
in
Kotlin
1.7.0
Release date: 9 June 2022
Kotlin 1.7.0 has been released. It unveils the Alpha version of the new Kotlin/JVM K2 compiler, stabilizes language features, and brings
performance improvements for the JVM, JS, and Native platforms.
The new Kotlin K2 compiler is in Alpha now, and it offers serious performance improvements. It is available only for the JVM, and none
90
of the compiler plugins, including kapt, work with it.
A new approach to the incremental compilation in Gradle. Incremental compilation is now also supported for changes made inside
dependent non-Kotlin modules and is compatible with Gradle.
We've stabilized opt-in requirement annotations, definitely non-nullable types, and builder inference.
There's now an underscore operator for type args. You can use it to automatically infer a type of argument when other types are
specified.
This release allows implementation by delegation to an inlined value of an inline class. You can now create lightweight wrappers that do
not allocate memory in most cases.
You can also find a short overview of the changes in this video:
Gif
New
Kotlin
K2
compiler
for
the
JVM
in
Alpha
This Kotlin release introduces the Alpha version of the new Kotlin K2 compiler. The new compiler aims to speed up the development of
new language features, unify all of the platforms Kotlin supports, bring performance improvements, and provide an API for compiler
extensions.
We've already published some detailed explanations of our new compiler and its benefits:
It's important to point out that with the Alpha version of the new K2 compiler we were primarily focused on performance improvements,
and it only works with JVM projects. It doesn't support Kotlin/JS, Kotlin/Native, or other multi-platform projects, and none of compiler
plugins, including kapt, work with it.
Project Current Kotlin compiler performance New K2 Kotlin compiler performance Performance boost
91
Project Current Kotlin compiler performance New K2 Kotlin compiler performance Performance boost
The KLOC/s performance numbers stand for the number of thousands of lines of code that the compiler processes per second.
You can check out the performance boost on your JVM projects and compare it with the results of the old compiler. To enable the Kotlin
K2 compiler, use the following compiler option:
-Xuse-k2
Also, the K2 compiler includes a number of bugfixes. Please note that even issues with State: Open from this list are in fact fixed in K2.
The next Kotlin releases will improve the stability of the K2 compiler and provide more features, so stay tuned!
If you face any performance issues with the Kotlin K2 compiler, please report them to our issue tracker.
Language
Kotlin 1.7.0 introduces support for implementation by delegation and a new underscore operator for type arguments. It also stabilizes
several language features introduced as previews in previous releases:
Allow
implementation
by
delegation
to
an
inlined
value
of
an
inline
class
If you want to create a lightweight wrapper for a value or class instance, it's necessary to implement all interface methods by hand.
Implementation by delegation solves this issue, but it did not work with inline classes before 1.7.0. This restriction has been removed, so
you can now create lightweight wrappers that do not allocate memory in most cases.
interface Bar {
92
fun foo() = "foo"
}
@JvmInline
value class BarWrapper(val bar: Bar): Bar by bar
fun main() {
val bw = BarWrapper(object: Bar {})
println(bw.foo())
}
Underscore
operator
for
type
arguments
Kotlin 1.7.0 introduces an underscore operator, _, for type arguments. You can use it to automatically infer a type argument when other
types are specified:
object Runner {
inline fun <reified S: SomeClass<T>, T> run(): T {
return S::class.java.getDeclaredConstructor().newInstance().execute()
}
}
fun main() {
// T is inferred as String because SomeImplementation derives from SomeClass<String>
val s = Runner.run<SomeImplementation, _>()
assert(s == "Test")
You can use the underscore operator in any position in the variables list to infer a type argument.
Stable
builder
inference
Builder inference is a special kind of type inference that is useful when calling generic builder functions. It helps the compiler infer the type
arguments of a call using the type information about other calls inside its lambda argument.
Starting with 1.7.0, builder inference is automatically activated if a regular type inference cannot get enough information about a type
without specifying the -Xenable-builder-inference compiler option, which was introduced in 1.6.0.
Stable
opt-in
requirements
Opt-in requirements are now Stable and do not require additional compiler configuration.
93
Before 1.7.0, the opt-in feature itself required the argument -opt-in=kotlin.RequiresOptIn to avoid a warning. It no longer requires this;
however, you can still use the compiler argument -opt-in to opt-in for other annotations, module-wise.
Stable
definitely
non-nullable
types
In Kotlin 1.7.0, definitely non-nullable types have been promoted to Stable. They provide better interoperability when extending generic
Java classes and interfaces.
You can mark a generic type parameter as definitely non-nullable at the use site with the new syntax T & Any. The syntactic form comes
from the notation for intersection types and is now limited to a type parameter with nullable upper bounds on the left side of & and a non-
nullable Any on the right side:
fun main() {
// OK
elvisLike<String>("", "").length
// Error: 'null' cannot be a value of a non-null type
elvisLike<String>("", null).length
// OK
elvisLike<String?>(null, "").length
// Error: 'null' cannot be a value of a non-null type
elvisLike<String?>(null, null).length
}
Kotlin/JVM
This release brings performance improvements for the Kotlin/JVM compiler and a new compiler option. Additionally, callable references to
functional interface constructors have become Stable. Note that since 1.7.0, the default target version for Kotlin/JVM compilations is now
1.8.
Compiler
performance
optimizations
Kotlin 1.7.0 introduces performance improvements for the Kotlin/JVM compiler. According to our benchmarks, compilation time has been
reduced by 10% on average compared to Kotlin 1.6.0. Projects with lots of usages of inline functions, for example, projects using
kotlinx.html, will compile faster thanks to the improvements to the bytecode postprocessing.
New
compiler
option:
-Xjdk-release
Kotlin 1.7.0 presents a new compiler option, -Xjdk-release. This option is similar to the javac's command-line --release option. The -Xjdk-
release option controls the target bytecode version and limits the API of the JDK in the classpath to the specified Java version. For
example, kotlinc -Xjdk-release=1.8 won't allow referencing java.lang.Module even if the JDK in the dependencies is version 9 or higher.
94
This option is not guaranteed to be effective for each JDK distribution.
Stable
callable
references
to
functional
interface
constructors
Callable references to functional interface constructors are now Stable. Learn how to migrate from an interface with a constructor function
to a functional interface using callable references.
Removed
JVM
target
version
1.6
The default target version for Kotlin/JVM compilations is 1.8. The 1.6 target has been removed.
Please migrate to JVM target 1.8 or above. Learn how to update the JVM target version for:
Gradle
Maven
Kotlin/Native
Kotlin 1.7.0 includes changes to Objective-C and Swift interoperability and stabilizes features that were introduced in previous releases. It
also brings performance improvements for the new memory manager along with other updates:
Performance
improvements
for
the
new
memory
manager
The new Kotlin/Native memory manager is in Alpha. It may change incompatibly and require manual migration in the future. We
would appreciate your feedback in YouTrack.
The new memory manager is still in Alpha, but it is on its way to becoming Stable. This release delivers significant performance
improvements for the new memory manager, especially in garbage collection (GC). In particular, concurrent implementation of the sweep
phase, introduced in 1.6.20, is now enabled by default. This helps reduce the time the application is paused for GC. The new GC
scheduler is better at choosing the GC frequency, especially for larger heaps.
95
Also, we've specifically optimized debug binaries, ensuring that the proper optimization level and link-time optimizations are used in the
implementation code of the memory manager. This helped us improve execution time by roughly 30% for debug binaries on our
benchmarks.
Try using the new memory manager in your projects to see how it works, and share your feedback with us in YouTrack.
Unified
compiler
plugin
ABI
with
JVM
and
JS
IR
backends
Starting with Kotlin 1.7.0, the Kotlin Multiplatform Gradle plugin uses the embeddable compiler jar for Kotlin/Native by default. This feature
was announced in 1.6.0 as Experimental, and now it's stable and ready to use.
This improvement is very handy for library authors, as it improves the compiler plugin development experience. Before this release, you
had to provide separate artifacts for Kotlin/Native, but now you can use the same compiler plugin artifacts for Native and other supported
platforms.
This feature might require plugin developers to take migration steps for their existing plugins.
Learn how to prepare your plugin for the update in this YouTrack issue.
Support
for
standalone
Android
executables
Kotlin 1.7.0 provides full support for generating standard executables for Android Native targets. It was introduced in 1.6.20, and now it's
enabled by default.
If you want to roll back to the previous behavior when Kotlin/Native generated shared libraries, use the following setting:
binaryOptions["androidProgramType"] = "nativeActivity"
Interop
with
Swift
async/await:
returning
Void
instead
of
KotlinUnit
Kotlin suspend functions now return the Void type instead of KotlinUnit in Swift. This is the result of the improved interop with Swift's
async/await. This feature was introduced in 1.6.20, and this release enables this behavior by default.
You don't need to use the kotlin.native.binary.unitSuspendFunctionObjCExport=proper property anymore to return the proper type for
such functions.
Prohibited
undeclared
exceptions
through
Objective-C
bridges
When you call Kotlin code from Swift/Objective-C code (or vice versa) and this code throws an exception, it should be handled by the
code where the exception occurred, unless you specifically allowed the forwarding of exceptions between languages with proper
conversion (for example, using the @Throws annotation).
Previously, Kotlin had another unintended behavior where undeclared exceptions could "leak" from one language to another in some
cases. Kotlin 1.7.0 fixes that issue, and now such cases lead to program termination.
So, for example, if you have a { throw Exception() } lambda in Kotlin and call it from Swift, in Kotlin 1.7.0 it will terminate as soon as the
exception reaches the Swift code. In previous Kotlin versions, such an exception could leak to the Swift code.
Improved
CocoaPods
integration
96
Starting with Kotlin 1.7.0, you no longer need to install the cocoapods-generate plugin if you want to integrate CocoaPods in your projects.
Previously, you needed to install both the CocoaPods dependency manager and the cocoapods-generate plugin to use CocoaPods, for
example, to handle iOS dependencies in Kotlin Multiplatform Mobile projects.
Now setting up the CocoaPods integration is easier, and we've resolved the issue when cocoapods-generate couldn't be installed on
Ruby 3 and later. Now the newest Ruby versions that work better on Apple M1 are also supported.
Overriding
the
Kotlin/Native
compiler
download
URL
Starting with Kotlin 1.7.0, you can customize the download URL for the Kotlin/Native compiler. This is useful when external links on the CI
are forbidden.
To override the default base URL https://download.jetbrains.com/kotlin/native/builds, use the following Gradle property:
kotlin.native.distribution.baseDownloadUrl=https://example.com
The downloader will append the native version and target OS to this base URL to ensure it downloads the actual compiler
distribution.
Kotlin/JS
Kotlin/JS is receiving further improvements to the JS IR compiler backend along with other updates that can make your development
experience better:
Performance
improvements
for
the
new
IR
backend
This release has some major updates that should improve your development experience:
Incremental compilation performance of Kotlin/JS has been significantly improved. It takes less time to build your JS projects.
Incremental rebuilds should now be roughly on par with the legacy backend in many cases now.
The Kotlin/JS final bundle requires less space, as we have significantly reduced the size of the final artifacts. We've measured up to a
20% reduction in the production bundle size compared to the legacy backend for some large projects.
Minification
for
member
names
when
using
IR
97
The Kotlin/JS IR compiler now uses its internal information about the relationships of your Kotlin classes and functions to apply more
efficient minification, shortening the names of functions, properties, and classes. This shrinks the resulting bundled applications.
This type of minification is automatically applied when you build your Kotlin/JS application in production mode and is enabled by default.
To disable member name minification, use the -Xir-minimized-member-names compiler flag:
kotlin {
js(IR) {
compilations.all {
compileKotlinTask.kotlinOptions.freeCompilerArgs += listOf("-Xir-minimized-member-names=false")
}
}
}
Support
for
older
browsers
via
polyfills
in
the
IR
backend
The IR compiler backend for Kotlin/JS now includes the same polyfills as the legacy backend. This allows code compiled with the new
compiler to run in older browsers that do not support all the methods from ES2015 used by the Kotlin standard library. Only those polyfills
actually used by the project are included in the final bundle, which minimizes their potential impact on the bundle size.
This feature is enabled by default when using the IR compiler, and you don't need to configure it.
Dynamically
load
JavaScript
modules
from
js
expressions
When working with the JavaScript modules, most applications use static imports, whose use is covered with the JavaScript module
integration. However, Kotlin/JS was missing a mechanism to load JavaScript modules dynamically at runtime in your applications.
Starting with Kotlin 1.7.0, the import statement from JavaScript is supported in js blocks, allowing you to dynamically bring packages into
your application at runtime:
Specify
environment
variables
for
JavaScript
test
runners
To tune Node.js package resolution or pass external information to Node.js tests, you can now specify environment variables used by the
JavaScript test runners. To define an environment variable, use the environment() function with a key-value pair inside the testTask block
in your build script:
kotlin {
js {
nodejs {
testTask {
environment("key", "value")
}
}
}
}
Standard
library
In Kotlin 1.7.0, the standard library has received a range of changes and improvements. They introduce new features, stabilize
experimental ones, and unify support for named capturing groups for Native, JS, and the JVM:
98
min() and max() collection functions return as non-nullable
min()
and
max()
collection
functions
return
as
non-nullable
In Kotlin 1.4.0, we renamed the min() and max() collection functions to minOrNull() and maxOrNull(). These new names better reflect their
behavior – returning null if the receiver collection is empty. It also helped align the functions' behavior with naming conventions used
throughout the Kotlin collections API.
The same was true of minBy(), maxBy(), minWith(), and maxWith(), which all got their *OrNull() synonyms in Kotlin 1.4.0. Older functions
affected by this change were gradually deprecated.
Kotlin 1.7.0 reintroduces the original function names, but with a non-nullable return type. The new min(), max(), minBy(), maxBy(),
minWith(), and maxWith() functions now strictly return the collection element or throw an exception.
fun main() {
val numbers = listOf<Int>()
println(numbers.maxOrNull()) // "null"
println(numbers.max()) // "Exception in... Collection is empty."
}
Regular
expression
matching
at
specific
indices
The Regex.matchAt() and Regex.matchesAt() functions, introduced in 1.5.30, are now Stable. They provide a way to check whether a
regular expression has an exact match at a particular position in a String or CharSequence.
fun main() {
val releaseText = "Kotlin 1.7.0 is on its way!"
// regular expression: one digit, dot, one digit, dot, one or more digits
val versionRegex = "\\d[.]\\d[.]\\d+".toRegex()
fun main() {
val releaseText = "Kotlin 1.7.0 is on its way!"
val versionRegex = "\\d[.]\\d[.]\\d+".toRegex()
99
}
Extended
support
for
previous
language
and
API
versions
To support library authors developing libraries that are meant to be consumable in a wide range of previous Kotlin versions, and to
address the increased frequency of major Kotlin releases, we have extended our support for previous language and API versions.
With Kotlin 1.7.0, we're supporting three previous language and API versions rather than two. This means Kotlin 1.7.0 supports the
development of libraries targeting Kotlin versions down to 1.4.0. For more information on backward compatibility, see Compatibility
modes.
Access
to
annotations
via
reflection
The KAnnotatedElement.findAnnotations() extension function, which was first introduced in 1.6.0, is now Stable. This reflection function
returns all annotations of a given type on an element, including individually applied and repeated annotations.
@Repeatable
annotation class Tag(val name: String)
@Tag("First Tag")
@Tag("Second Tag")
fun taggedFunction() {
println("I'm a tagged function!")
}
fun main() {
val x = ::taggedFunction
val foo = x as KAnnotatedElement
println(foo.findAnnotations<Tag>())
// [@Tag(name=First Tag), @Tag(name=Second Tag)]
}
Stable
deep
recursive
functions
Deep recursive functions have been available as an experimental feature since Kotlin 1.4.0, and they are now Stable in Kotlin 1.7.0. Using
DeepRecursiveFunction, you can define a function that keeps its stack on the heap instead of using the actual call stack. This allows you
to run very deep recursive computations. To call a deep recursive function, invoke it.
In this example, a deep recursive function is used to calculate the depth of a binary tree recursively. Even though this sample function calls
itself recursively 100,000 times, no StackOverflowError is thrown:
fun main() {
// Generate a tree with a depth of 100_000
val deepTree = generateSequence(Tree(null, null)) { prev ->
Tree(prev, null)
}.take(100_000).last()
println(calculateDepth(deepTree)) // 100000
100
}
Consider using deep recursive functions in your code where your recursion depth exceeds 1000 calls.
Time
marks
based
on
inline
classes
for
default
time
source
Kotlin 1.7.0 improves the performance of time measurement functionality by changing the time marks returned by TimeSource.Monotonic
into inline value classes. This means that calling functions like markNow(), elapsedNow(), measureTime(), and measureTimedValue()
doesn't allocate wrapper classes for their TimeMark instances. Especially when measuring a piece of code that is part of a hot path, this
can help minimize the performance impact of the measurement:
@OptIn(ExperimentalTime::class)
fun main() {
val mark = TimeSource.Monotonic.markNow() // Returned `TimeMark` is inline class
val elapsedDuration = mark.elapsedNow()
}
This optimization is only available if the time source from which the TimeMark is obtained is statically known to be
TimeSource.Monotonic.
New
experimental
extension
functions
for
Java
Optionals
Kotlin 1.7.0 comes with new convenience functions that simplify working with Optional classes in Java. These new functions can be used
to unwrap and convert optional objects on the JVM and help make working with Java APIs more concise.
The getOrNull(), getOrDefault(), and getOrElse() extension functions allow you to get the value of an Optional if it's present. Otherwise, you
get a default value, null, or a value returned by a function, respectively:
println(presentOptional.getOrNull())
// "I'm here!"
println(absentOptional.getOrNull())
// null
println(absentOptional.getOrDefault("Nobody here!"))
// "Nobody here!"
println(absentOptional.getOrElse {
println("Optional was absent!")
"Default value!"
})
// "Optional was absent!"
// "Default value!"
The toList(), toSet(), and asSequence() extension functions convert the value of a present Optional to a list, set, or sequence, or return an
empty collection otherwise. The toCollection() extension function appends the Optional value to an already existing destination collection:
101
absentOptional.toCollection(myCollection)
println(myCollection)
// []
presentOptional.toCollection(myCollection)
println(myCollection)
// ["I'm here!"]
val list = listOf(presentOptional, absentOptional).flatMap { it.asSequence() }
println(list)
// ["I'm here!"]
These extension functions are being introduced as Experimental in Kotlin 1.7.0. You can learn more about Optional extensions in this
KEEP. As always, we welcome your feedback in the Kotlin issue tracker.
Support
for
named
capturing
groups
in
JS
and
Native
Starting with Kotlin 1.7.0, named capturing groups are supported not only on the JVM, but on the JS and Native platforms as well.
To give a name to a capturing group, use the (?<name>group) syntax in your regular expression. To get the text matched by a group, call
the newly introduced MatchGroupCollection.get() function and pass the group name.
fun main() {
val regex = "\\b(?<city>[A-Za-z\\s]+),\\s(?<state>[A-Z]{2}):\\s(?<areaCode>[0-9]{3})\\b".toRegex()
val input = "Coordinates: Austin, TX: 123"
val match = regex.find(input)!!
println(match.groups["city"]?.value) // "Austin" — by name
println(match.groups[2]?.value) // "TX" — by number
}
Named backreferencing
You can now also use group names when backreferencing groups. Backreferences match the same text that was previously matched by a
capturing group. For this, use the \k<name> syntax in your regular expression:
fun backRef() {
val regex = "(?<title>\\w+), yes \\k<title>".toRegex()
val match = regex.find("Do you copy? Sir, yes Sir!")!!
println(match.value) // "Sir, yes Sir"
println(match.groups["title"]?.value) // "Sir"
}
Occurrences of ${name} in the replacement string are substituted with the subsequences corresponding to the captured groups with the
specified name. You can compare replacements in group references by name and index:
fun dateReplace() {
val dateRegex = Regex("(?<dd>\\d{2})-(?<mm>\\d{2})-(?<yyyy>\\d{4})")
val input = "Date of birth: 27-04-2022"
println(dateRegex.replace(input, "\${yyyy}-\${mm}-\${dd}")) // "Date of birth: 2022-04-27" — by name
println(dateRegex.replace(input, "\$3-\$2-\$1")) // "Date of birth: 2022-04-27" — by number
102
}
Gradle
This release introduces new build reports, support for Gradle plugin variants, new statistics in kapt, and a lot more:
Changes to the minimum supported versions of Gradle and the Android Gradle plugin
A
new
approach
to
incremental
compilation
The new approach to incremental compilation is Experimental. It may be dropped or changed at any time. Opt-in is required
(see the details below). We encourage you to use it only for evaluation purposes, and we would appreciate your feedback in
YouTrack.
In Kotlin 1.7.0, we've reworked incremental compilation for cross-module changes. Now incremental compilation is also supported for
changes made inside dependent non-Kotlin modules, and it is compatible with the Gradle build cache. Support for compilation avoidance
has also been improved.
We expect you'll see the most significant benefit of the new approach if you use the build cache or frequently make changes in non-Kotlin
Gradle modules. Our tests for the Kotlin project on the kotlin-gradle-plugin module show an improvement of greater than 80% for the
changes after the cache hit.
To try this new approach, set the following option in your gradle.properties:
kotlin.incremental.useClasspathSnapshot=true
The new approach to incremental compilation is currently available for the JVM backend in the Gradle build system only.
Learn how the new approach to incremental compilation is implemented under the hood in this blog post.
Our plan is to stabilize this technology and add support for other backends (JS, for instance) and build systems. We'd appreciate your
reports in YouTrack about any issues or strange behavior you encounter in this compilation scheme. Thank you!
103
The Kotlin team is very grateful to Ivan Gavrilovic, Hung Nguyen, Cédric Champeau, and other external contributors for their help.
Build
reports
for
Kotlin
compiler
tasks
Kotlin build reports are Experimental. They may be dropped or changed at any time. Opt-in is required (see details below). Use
them only for evaluation purposes. We appreciate your feedback on them in YouTrack.
Kotlin 1.7.0 introduces build reports that help track compiler performance. Reports contain the durations of different compilation phases
and reasons why compilation couldn't be incremental.
Build reports come in handy when you want to investigate issues with compiler tasks, for example:
When the Gradle build takes too much time and you want to understand the root cause of the poor performance.
When the compilation time for the same project differs, sometimes taking seconds, sometimes taking minutes.
To enable build reports, declare where to save the build report output in gradle.properties:
kotlin.build.report.output=file
build_scan saves build reports in the custom values section of the build scan.
The Gradle Enterprise plugin limits the number of custom values and their length. In big projects, some values could be lost.
http posts build reports using HTTP(S). The POST method sends metrics in the JSON format. Data may change from version to version.
You can see the current version of the sent data in the Kotlin repository.
There are two common cases that analyzing build reports for long-running compilations can help you resolve:
The build wasn't incremental. Analyze the reasons and fix underlying problems.
The build was incremental, but took too much time. Try to reorganize source files — split big files, save separate classes in different
files, refactor large classes, declare top-level functions in different files, and so on.
You are welcome to try using build reports in your infrastructure. If you have any feedback, encounter any issues, or want to suggest
improvements, please don't hesitate to report them in our issue tracker. Thank you!
Bumping
minimum
supported
versions
Starting with Kotlin 1.7.0, the minimum supported Gradle version is 6.7.1. We had to raise the version to support Gradle plugin variants
and the new Gradle API. In the future, we should not have to raise the minimum supported version as often, thanks to the Gradle plugin
variants feature.
Also, the minimal supported Android Gradle plugin version is now 3.6.4.
104
Support
for
Gradle
plugin
variants
Gradle 7.0 introduced a new feature for Gradle plugin authors — plugins with variants. This feature makes it easier to add support for new
Gradle features while maintaining compatibility for Gradle versions below 7.1. Learn more about variant selection in Gradle.
With Gradle plugin variants, we can ship different Kotlin Gradle plugin variants for different Gradle versions. The goal is to support the base
Kotlin compilation in the main variant, which corresponds to the oldest supported versions of Gradle. Each variant will have
implementations for Gradle features from a corresponding release. The latest variant will support the widest Gradle feature set. With this
approach, we can extend support for older Gradle versions with limited functionality.
Currently, there are only two variants of the Kotlin Gradle plugin:
To check which variant your build uses, enable the --info log level and find a string in the output starting with Using Kotlin Gradle plugin,
for example, Using Kotlin Gradle plugin main variant.
Here are workarounds for some known issues with variant selection in Gradle:
Plugin variants are ignored when a plugin is added as the buildSrc common dependency
Updates
in
the
Kotlin
Gradle
plugin
API
The Kotlin Gradle plugin API artifact has received several improvements:
There are new interfaces for Kotlin/JVM and Kotlin/kapt tasks with user-configurable inputs.
There is a new KotlinBasePlugin interface that all Kotlin plugins inherit from. Use this interface when you want to trigger some
configuration action whenever any Kotlin Gradle plugin (JVM, JS, Multiplatform, Native, and other platforms) is applied:
project.plugins.withType<org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin>() {
// Configure your action here
}
You can leave your feedback about the KotlinBasePlugin in this YouTrack ticket.
We've laid the groundwork for the Android Gradle plugin to configure Kotlin compilation within itself, meaning you won't need to add
the Kotlin Android Gradle plugin to your build. Follow Android Gradle Plugin release announcements to learn about the added support
and try it out!
The
sam-with-receiver
plugin
is
available
via
the
plugins
API
The sam-with-receiver compiler plugin is now available via the Gradle plugins DSL:
plugins {
id("org.jetbrains.kotlin.plugin.sam.with.receiver") version "$kotlin_version"
}
105
Changes
in
compile
tasks
Compile tasks have received lots of changes in this release:
Kotlin compile tasks no longer inherit the Gradle AbstractCompile task. They inherit only the DefaultTask.
The AbstractCompile task has the sourceCompatibility and targetCompatibility inputs. Since the AbstractCompile task is no longer
inherited, these inputs are no longer available in Kotlin users' scripts.
The SourceTask.stableSources input is no longer available, and you should use the sources input. setSource(...) methods that are still
available.
All compile tasks now use the libraries input for a list of libraries required for compilation. The KotlinCompile task still has the
deprecated Kotlin property classpath, which will be removed in future releases.
Compile tasks still implement the PatternFilterable interface, which allows the filtering of Kotlin sources. The sourceFilesExtensions
input was removed in favor of using PatternFilterable methods.
The deprecated Gradle destinationDir: File output was replaced with the destinationDirectory: DirectoryProperty output.
The Kotlin/Native AbstractNativeCompile task now inherits the AbstractKotlinCompileTool base class. This is an initial step toward
integrating Kotlin/Native build tools into all the other tools.
Statistics
of
generated
files
by
each
annotation
processor
in
kapt
The kotlin-kapt Gradle plugin already reports performance statistics for each processor. Starting with Kotlin 1.7.0, it can also report
statistics on the number of generated files for each annotation processor.
This is useful to track if there are unused annotation processors as a part of the build. You can use the generated report to find modules
that trigger unnecessary annotation processors and update the modules to prevent that.
kapt {
showProcessorStats = true
}
kapt.verbose=true
You can also enable verbose output via the command line option verbose.
The statistics will appear in the logs with the info level. You'll see the Annotation processor stats: line followed by statistics on the
execution time of each annotation processor. After these lines, there will be the Generated files report: line followed by statistics on the
number of generated files for each annotation processor. For example:
106
[INFO] Annotation processor stats:
[INFO] org.mapstruct.ap.MappingProcessor: total: 290 ms, init: 1 ms, 3 round(s): 289 ms, 0 ms, 0 ms
[INFO] Generated files report:
[INFO] org.mapstruct.ap.MappingProcessor: total sources: 2, sources per round: 2, 0, 0
Deprecation
of
the
kotlin.compiler.execution.strategy
system
property
Kotlin 1.6.20 introduced new properties for defining a Kotlin compiler execution strategy. In Kotlin 1.7.0, a deprecation cycle has started
for the old system property kotlin.compiler.execution.strategy in favor of the new properties.
When using the kotlin.compiler.execution.strategy system property, you'll receive a warning. This property will be deleted in future
releases. To preserve the old behavior, replace the system property with the Gradle property of the same name. You can do this in
gradle.properties, for example:
kotlin.compiler.execution.strategy=out-of-process
You can also use the compile task property compilerExecutionStrategy. Learn more about this on the Gradle page.
Removal
of
deprecated
options,
methods,
and
plugins
sourceSets {
all {
languageSettings.optIn("org.mylibrary.OptInAnnotation")
}
}
The kotlinOptions.jdkHome compiler option was deprecated in 1.5.30 and has been removed in the current release. Gradle builds now
fail if they contain this option. We encourage you to use Java toolchains, which have been supported since Kotlin 1.5.30.
The deprecated 'noStdlib' compiler option has also been removed. The Gradle plugin uses the kotlin.stdlib.default.dependency=true
property to control whether the Kotlin standard library is present.
107
configured.
In Kotlin 1.6.0, we changed the deprecation level of the KotlinGradleSubplugin class to 'ERROR'. Developers used this class for writing
compiler plugins. In this release, this class has been removed. Use the KotlinCompilerPluginSupportPlugin class instead.
The best practice is to use Kotlin plugins with versions 1.7.0 and higher throughout your project.
kotlin {
jvmToolchain {
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)
}
}
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)
}
}
Migrating
to
Kotlin
1.7.0
Install
Kotlin
1.7.0
IntelliJ IDEA 2022.1 and Android Studio Chipmunk (212) automatically suggest updating the Kotlin plugin to 1.7.0.
For IntelliJ IDEA 2022.2, and Android Studio Dolphin (213) or Android Studio Electric Eel (221), the Kotlin plugin 1.7.0 will be
delivered with upcoming IntelliJ IDEA and Android Studios updates.
The new command-line compiler is available for download on the GitHub release page.
Migrate
existing
or
start
a
new
project
with
Kotlin
1.7.0
To migrate existing projects to Kotlin 1.7.0, change the Kotlin version to 1.7.0 and reimport your Gradle or Maven project. Learn how to
update to Kotlin 1.7.0.
To start a new project with Kotlin 1.7.0, update the Kotlin plugin and run the Project Wizard from File | New | Project.
108
Compatibility
guide
for
Kotlin
1.7.0
Kotlin 1.7.0 is a feature release and can, therefore, bring changes that are incompatible with your code written for earlier versions of the
language. Find the detailed list of such changes in the Compatibility guide for Kotlin 1.7.0.
What's
new
in
Kotlin
1.6.20
Release date: 4 April 2022
Kotlin 1.6.20 reveals previews of the future language features, makes the hierarchical structure the default for multiplatform projects, and
brings evolutionary improvements to other components.
You can also find a short overview of the changes in this video:
Gif
Language
In Kotlin 1.6.20, you can try two new language features:
Prototype
of
context
receivers
for
Kotlin/JVM
The feature is a prototype available only for Kotlin/JVM. With -Xcontext-receivers enabled, the compiler will produce pre-release
binaries that cannot be used in production code. Use context receivers only in your toy projects. We appreciate your feedback in
YouTrack.
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:
109
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.
interface LoggingContext {
val log: Logger // This context provides a reference to a logger
}
context(LoggingContext)
fun startBusinessOperation() {
// You can access the log property since LoggingContext is an implicit receiver
log.info("Operation has started")
}
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.
With -Xcontext-receivers enabled, the compiler will produce pre-release binaries that cannot be used in production code
Try the feature in your toy projects and share your thoughts and experience with us in this YouTrack issue. If you run into any problems,
please file a new issue.
Definitely
non-nullable
types
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.
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:
fun main() {
// OK
elvisLike<String>("", "").length
// Error: 'null' cannot be a value of a non-null type
elvisLike<String>("", null).length
// OK
elvisLike<String?>(null, "").length
// Error: 'null' cannot be a value of a non-null type
elvisLike<String?>(null, null).length
}
110
Set the language version to 1.7 to enable the feature:
Kotlin
kotlin {
sourceSets.all {
languageSettings.apply {
languageVersion = "1.7"
}
}
}
Groovy
kotlin {
sourceSets.all {
languageSettings {
languageVersion = '1.7'
}
}
}
Kotlin/JVM
Kotlin 1.6.20 introduces:
Compatibility improvements of default methods in JVM interfaces: new @JvmDefaultWithCompatibility annotation for interfaces and
compatibility changes in the -Xjvm-default modes
New
@JvmDefaultWithCompatibility
annotation
for
interfaces
Kotlin 1.6.20 introduces the new annotation @JvmDefaultWithCompatibility: use it along with the -Xjvm-default=all compiler option to
create the default method in JVM interface for any non-abstract member in any Kotlin interface.
If there are clients that use your Kotlin interfaces compiled without the -Xjvm-default=all option, they may be binary-incompatible with the
code compiled with this option. Before Kotlin 1.6.20, to avoid this compatibility issue, the recommended approach was to use the -Xjvm-
default=all-compatibility mode and also the @JvmDefaultWithoutCompatibility annotation for interfaces that didn't need this type of
compatibility.
You could easily forget to add the annotation when a new interface was added.
Usually there are more interfaces in non-public parts than in the public API, so you end up having this annotation in many places in your
code.
Now, you can use the -Xjvm-default=all mode and mark interfaces with the @JvmDefaultWithCompatibility annotation. This allows you to
add this annotation to all interfaces in the public API once, and you won't need to use any annotations for new non-public code.
111
Leave your feedback about this new annotation in this YouTrack ticket.
Compatibility
changes
in
the
-Xjvm-default
modes
Kotlin 1.6.20 adds the option to compile modules in the default mode (the -Xjvm-default=disable compiler option) against modules
compiled with the -Xjvm-default=all or -Xjvm-default=all-compatibility modes. As before, compilations will also be successful if all modules
have the -Xjvm-default=all or -Xjvm-default=all-compatibility modes. You can leave your feedback in this YouTrack issue.
Kotlin 1.6.20 deprecates the compatibility and enable modes of the compiler option -Xjvm-default. There are changes in other modes'
descriptions regarding the compatibility, but the overall logic remains the same. You can check out the updated descriptions.
For more information about default methods in the Java interop, see the interoperability documentation and this blog post.
Support
for
parallel
compilation
of
a
single
module
in
the
JVM
backend
Support for parallel compilation of a single module in the JVM backend is Experimental. It may be dropped or changed at any
time. Opt-in is required (see details below), and you should use it only for evaluation purposes. We would appreciate your
feedback on it in YouTrack.
We are continuing our work to improve the new JVM IR backend compilation time. 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 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
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.
It requires more JVM heap by design. The amount of heap is proportional to the number of threads
Support
for
callable
references
to
functional
interface
constructors
Support for callable references to functional interface constructors is Experimental. It may be dropped or changed at any time.
Opt-in is required (see details below), and you should use it only for evaluation purposes. We would appreciate your feedback
on it in YouTrack.
Support for callable references to functional interface constructors adds a source-compatible way to migrate from an interface with a
112
constructor function to a functional interface.
interface Printer {
fun print()
}
fun Printer(block: () -> Unit): Printer = object : Printer { override fun print() = block() }
With callable references to functional interface constructors enabled, this code can be replaced with just a functional interface declaration:
Its constructor will be created implicitly, and any code using the ::Printer function reference will compile. For example:
documentsStorage.addPrinter(::Printer)
Preserve the binary compatibility by marking the legacy function Printer with the @Deprecated annotation with DeprecationLevel.HIDDEN:
Kotlin/Native
Kotlin/Native 1.6.20 marks continued development of its new components. We've taken another step toward consistent experience with
Kotlin on other platforms:
Performance improvements
An
update
on
the
new
memory
manager
113
The new Kotlin/Native memory manager is in Alpha. It may change incompatibly and require manual migration in the future. We
would appreciate your feedback on it in YouTrack.
With Kotlin 1.6.20, you can try the Alpha version of the new Kotlin/Native memory manager. It eliminates the differences between the JVM
and Native platforms to provide a consistent developer experience in multiplatform projects. For example, you'll have a much easier time
creating new cross-platform mobile applications that work on both Android and iOS.
The new Kotlin/Native memory manager lifts restrictions on object-sharing between threads. It also provides leak-free concurrent
programming primitives that are safe and don't require any special management or annotations.
The new memory manager will become the default in future versions, so we encourage you to try it now. Check out our blog post to learn
more about the new memory manager and explore demo projects, or jump right to the migration instructions to try it yourself.
Try using the new memory manager on your projects to see how it works and share feedback in our issue tracker, YouTrack.
Concurrent
implementation
for
the
sweep
phase
in
new
memory
manager
If you have already switched to our new memory manager, which was announced in Kotlin 1.6, you might notice a huge execution time
improvement: our benchmarks show 35% improvement on average. Starting with 1.6.20, there is also a concurrent implementation for the
sweep phase available for the new memory manager. This should also improve the performance and decrease the duration of garbage
collector pauses.
To enable the feature for the new Kotlin/Native memory manager, pass the following compiler option:
-Xgc=cms
Feel free to share your feedback on the new memory manager performance in this YouTrack issue.
Instantiation
of
annotation
classes
In Kotlin 1.6.0, instantiation of annotation classes became Stable for Kotlin/JVM and Kotlin/JS. The 1.6.20 version delivers support for
Kotlin/Native.
Interop
with
Swift
async/await:
returning
Void
instead
of
KotlinUnit
Concurrency interoperability with Swift async/await is Experimental. It may be dropped or changed at any time. You should use
it only for evaluation purposes. We would appreciate your feedback on it in YouTrack.
We've continued working on the experimental interop with Swift's async/await (available since Swift 5.5). Kotlin 1.6.20 differs from
previous versions in the way it works with suspend functions with the Unit return type.
Previously, such functions were presented in Swift as async functions returning KotlinUnit. However, the proper return type for them is
Void, similar to non-suspending functions.
To avoid breaking the existing code, we're introducing a Gradle property that makes the compiler translate Unit-returning suspend
functions to async Swift with the Void return type:
# gradle.properties
114
kotlin.native.binary.unitSuspendFunctionObjCExport=proper
Better
stack
traces
with
libbacktrace
Using libbacktrace for resolving source locations is Experimental. It may be dropped or changed at any time. You should use it
only for evaluation purposes. We would appreciate your feedback on it in YouTrack.
Kotlin/Native is now able to produce detailed stack traces with file locations and line numbers for better debugging of linux* (except
linuxMips32 and linuxMipsel32) and androidNative* targets.
This feature uses the libbacktrace library under the hood. Take a look at the following code to see an example of the difference:
Before 1.6.20:
Before 1.6.20:
115
(kotlin.String?){} + 88 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-
native/runtime/src/main/kotlin/kotlin/Throwable.kt:24:37) at 1 example.kexe 0x106696bd6 kfun:kotlin.Exception#<init>
(kotlin.String?){} + 86 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-
native/runtime/src/main/kotlin/kotlin/Exceptions.kt:23:44) at 2 example.kexe 0x106696cc6
kfun:kotlin.RuntimeException#<init>(kotlin.String?){} + 86 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-
native/runtime/src/main/kotlin/kotlin/Exceptions.kt:34:44) at 3 example.kexe 0x106697016
kfun:kotlin.IllegalStateException#<init>(kotlin.String?){} + 86 (/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/kotlin-
native/runtime/src/main/kotlin/kotlin/Exceptions.kt:70:44) at 4 example.kexe 0x106689d35 kfun:#bar(){} + 117 [inlined]
(/opt/buildAgent/work/c3a91df21e46e2c8/kotlin/libraries/stdlib/src/kotlin/util/Preconditions.kt:143:56) >> at 5
example.kexe 0x106689d35 kfun:#bar(){} + 117 [inlined] (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:4:5) at
6 example.kexe 0x106689d35 kfun:#bar(){} + 117 (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:2:13) at 7
example.kexe 0x106689cac kfun:#main(){} + 12 (/private/tmp/backtrace/src/commonMain/kotlin/app.kt:1:14) ...
To produce better stack traces with libbacktrace, add the following line to gradle.properties:
# gradle.properties
kotlin.native.binary.sourceInfoType=libbacktrace
Please tell us how debugging Kotlin/Native with libbacktrace works for you in this YouTrack issue.
Support
for
standalone
Android
executables
Previously, Android Native executables in Kotlin/Native were not actually executables but shared libraries that you could use as a
NativeActivity. Now there's an option to generate standard executables for Android Native targets.
For that, in the build.gradle(.kts) part of your project, configure the executable block of your androidNative target. Add the following binary
option:
kotlin {
androidNativeX64("android") {
binaries {
executable {
binaryOptions["androidProgramType"] = "standalone"
}
}
}
}
Note that this feature will become the default in Kotlin 1.7.0. If you want to preserve the current behavior, use the following setting:
binaryOptions["androidProgramType"] = "nativeActivity"
Performance
improvements
We are working hard on Kotlin/Native to speed up the compilation process and improve your developing experience.
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:
20% reduction in the code size of both release and debug 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
116
structure LLVM IR for every function, and optimized the compiler caches.
Improved
error
handling
during
cinterop
modules
import
This release introduces improved error handling for cases where you import an Objective-C module using the cinterop tool (as is typical for
CocoaPods pods). Previously, if you got an error while trying to work with an Objective-C module (for instance, when dealing with a
compilation error in a header), you received an uninformative error message, such as fatal error: could not build module $name. We
expanded upon this part of the cinterop tool, so you'll get an error message with an extended description.
Support
for
Xcode
13
libraries
Libraries delivered with Xcode 13 have full support as of this release. Feel free to access them from anywhere in your Kotlin code.
Kotlin
Multiplatform
1.6.20 brings the following notable updates to Kotlin Multiplatform:
Hierarchical structure support is now default for all new multiplatform projects
Kotlin CocoaPods Gradle plugin received several useful features for CocoaPods integration
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.
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.
117
iOS hierarchy example
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.
If you've already turned it on manually, you can remove the deprecated options from gradle.properties:
# gradle.properties
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false // or 'true', depending on your previous setup
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 ingradle.properties:
# gradle.properties
kotlin.mpp.hierarchicalStructureSupport=false
Try it now and report any difficulties you encounter to our issue tracker.
118
Kotlin
CocoaPods
Gradle
plugin
To simplify CocoaPods integration, Kotlin 1.6.20 delivers the following features:
The CocoaPods plugin now has tasks that build XCFrameworks with all registered targets and generate the Podspec file. This can be
useful when you don't want to integrate with Xcode directly, but you want to build artifacts and deploy them to your local CocoaPods
repository.
If you use CocoaPods integration in your projects, you're used to specifying the required Pod version for the entire Gradle project. Now
you have more options:
You can now configure the CocoaPod name in the cocoapods block instead of changing the name of the whole Gradle project.
The CocoaPods plugin introduces a new extraSpecAttributes property, which you can use to configure properties in a Podspec file that
were previously hard-coded, like libraries or vendored_frameworks.
kotlin {
cocoapods {
version = "1.0"
name = "MyCocoaPod"
extraSpecAttributes["social_media_url"] = 'https://twitter.com/kotlin'
extraSpecAttributes["vendored_frameworks"] = 'CustomFramework.xcframework'
extraSpecAttributes["libraries"] = 'xml'
}
}
Kotlin/JS
Kotlin/JS improvements in 1.6.20 mainly affect the IR compiler:
Incremental
compilation
for
development
binaries
with
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
119
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:
# gradle.properties
kotlin.incremental.js.ir=true // false by default
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.
Please tell us what you think of using incremental compilation with your Kotlin/JS projects in this YouTrack issue.
Lazy
initialization
of
top-level
properties
by
default
with
IR
compiler
In Kotlin 1.4.30, we presented a prototype of lazy initialization of top-level properties in the JS IR compiler. By eliminating the need to
initialize all properties when the application launches, lazy initialization reduces the startup time. Our measurements showed about a 10%
speed-up on a real-life Kotlin/JS application.
Now, having polished and properly tested this mechanism, we're making lazy initialization the default for top-level properties in the IR
compiler.
// lazy initialization
val a = run {
val result = // intensive computations
println(result)
result
} // run is executed upon the first usage of the variable
If for some reason you need to initialize a property eagerly (upon the application start), mark it with the @EagerInitialization annotation.
Separate
JS
files
for
project
modules
by
default
with
IR
compiler
Previously, the JS IR compiler offered an ability to generate separate .js files for project modules. This was an alternative to the default
option – a single .js file for the whole project. This file might be too large and inconvenient to use, because whenever you want to use a
function from your project, you have to include the entire JS file as a dependency. Having multiple files adds flexibility and decreases the
size of such dependencies. This feature was available with the -Xir-per-module compiler option.
Starting from 1.6.20, the JS IR compiler generates separate .js files for project modules by default.
Compiling the project into a single .js file is now available with the following Gradle property:
# gradle.properties
kotlin.js.ir.output.granularity=whole-program // `per-module` is the default
In previous releases, the experimental per-module mode (available via the -Xir-per-module=true flag) invoked main() functions in each
module. This is inconsistent with the regular 'single .js' mode. Starting with 1.6.20, the main() function will be invoked in the main module
only in both cases. If you do need to run some code when a module is loaded, you can use top-local properties annotated with the
@EagerInitialization annotation. See Lazy initialization of top-level properties by default (IR).
Char
class
optimization
The Char class is now handled by the Kotlin/JS compiler without introducing boxing (similar to inline classes). This speeds up operations
on chars in Kotlin/JS code.
120
Aside from the performance improvement, this changes the way Char is exported to JavaScript: it's now translated to Number.
Improvements
to
export
and
TypeScript
declaration
generation
Kotlin 1.6.20 is bringing multiple fixes and improvements to the export mechanism (the @JsExport annotation), including the generation of
TypeScript declarations (.d.ts). We've added the ability to export interfaces and enums, and we've fixed the export behavior in some
corner cases that were reported to us previously. For more details, see the list of export improvements in YouTrack.
@AfterTest
guarantees
for
asynchronous
tests
Kotlin 1.6.20 makes @AfterTest functions work properly with asynchronous tests on Kotlin/JS. If a test function's return type is statically
resolved to Promise, the compiler now schedules the execution of the @AfterTest function to the corresponding then() callback.
Security
Kotlin 1.6.20 introduces a couple of features to improve the security of your code:
Using
relative
paths
in
klibs
A library in klib format contains a serialized IR representation of source files, which also includes their paths for generating proper debug
information. Before Kotlin 1.6.20, stored file paths were absolute. Since the library author may not want to share absolute paths, the 1.6.20
version comes with an alternative option.
If you are publishing a klib and want to use only relative paths of source files in the artifact, you can now pass the -Xklib-relative-path-base
compiler option with one or multiple base paths of source files:
Kotlin
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class).configureEach {
// $base is a base path of source files
kotlinOptions.freeCompilerArgs += "-Xklib-relative-path-base=$base"
}
Groovy
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
// $base is a base path of source files
freeCompilerArgs += "-Xklib-relative-path-base=$base"
}
}
Persisting
yarn.lock
for
Kotlin/JS
Gradle
projects
121
The feature was backported to Kotlin 1.6.10.
The Kotlin/JS Gradle plugin now provides an ability to persist the yarn.lock file, making it possible to lock the versions of the npm
dependencies for your project without additional Gradle configuration. The feature brings changes to the default project structure by
adding the auto-generated kotlin-js-store directory to the project root. It holds the yarn.lock file inside.
We strongly recommend committing the kotlin-js-store directory and its contents to your version control system. Committing lockfiles to
your version control system is a recommended practice because it ensures your application is being built with the exact same dependency
tree on all machines, regardless of whether those are development environments on other machines or CI/CD services. Lockfiles also
prevent your npm dependencies from being silently updated when a project is checked out on a new machine, which is a security
concern.
Tools like Dependabot can also parse the yarn.lock files of your Kotlin/JS projects, and provide you with warnings if any npm package you
depend on is compromised.
If needed, you can change both directory and lockfile names in the build script:
Kotlin
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin> {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().lockFileDirectory =
project.rootDir.resolve("my-kotlin-js-store")
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().lockFileName = "my-
yarn.lock"
}
Groovy
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin) {
rootProject.extensions.getByType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension).lockFileDirectory
=
file("my-kotlin-js-store")
rootProject.extensions.getByType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension).lockFileName =
'my-yarn.lock'
}
Changing the name of the lockfile may cause dependency inspection tools to no longer pick up the file.
Installation
of
npm
dependencies
with
--ignore-scripts
by
default
The Kotlin/JS Gradle plugin now prevents the execution of lifecycle scripts during the installation of npm dependencies by default. The
change is aimed at reducing the likelihood of executing malicious code from compromised npm packages.
To roll back to the old configuration, you can explicitly enable lifecycle scripts execution by adding the following lines to build.gradle(.kts):
122
Kotlin
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin> {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().ignoreScripts = false
}
Groovy
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin) {
rootProject.extensions.getByType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension).ignoreScripts =
false
}
Gradle
Kotlin 1.6.20 brings the following changes for the Kotlin Gradle Plugin:
New properties kotlin.compiler.execution.strategy and compilerExecutionStrategy for defining a Kotlin compiler execution strategy
Properties
for
defining
Kotlin
compiler
execution
strategy
Before Kotlin 1.6.20, you used the system property -Dkotlin.compiler.execution.strategy to define a Kotlin compiler execution strategy.
This property might have been inconvenient in some cases. Kotlin 1.6.20 introduces a Gradle property with the same name,
kotlin.compiler.execution.strategy, and the compile task property compilerExecutionStrategy.
The system property still works, but it will be removed in future releases.
The task property compilerExecutionStrategy takes priority over the system property and the Gradle property
kotlin.compiler.execution.strategy.
There are three compiler execution strategies that you can assign to these properties:
Daemon Inside its own daemon process Yes The default strategy. Can be shared between different Gradle
daemons
123
Strategy Where Kotlin compiler is Incremental Other characteristics
executed compilation
In process Inside the Gradle daemon No May share the heap with the Gradle daemon
process
Accordingly, the available values for kotlin.compiler.execution.strategy properties (both system and Gradle's) are:
1. daemon (default)
2. in-process
3. out-of-process
# gradle.properties
kotlin.compiler.execution.strategy=out-of-process
1. org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.DAEMON (default)
2. org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.IN_PROCESS
3. org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy.OUT_OF_PROCESS
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
// …
tasks.withType<KotlinCompile>().configureEach {
compilerExecutionStrategy.set(KotlinCompilerExecutionStrategy.IN_PROCESS)
}
Deprecation
of
build
options
for
kapt
and
coroutines
In Kotlin 1.6.20, we changed deprecation levels of the properties:
We deprecated the ability to run kapt via the Kotlin daemon with kapt.use.worker.api – now it produces a warning to Gradle's output.
By default, kapt has been using Gradle workers since the 1.3.70 release, and we recommend sticking to this method.
We deprecated the kotlin.experimental.coroutines Gradle DSL option and the kotlin.coroutines property used in gradle.properties. Just
124
use suspending functions or add the kotlinx.coroutines dependency to your build.gradle(.kts) file.
Removal
of
the
kotlin.parallel.tasks.in.project
build
option
In Kotlin 1.5.20, we announced the deprecation of the build option kotlin.parallel.tasks.in.project. This option has been removed in Kotlin
1.6.20.
Depending on the project, parallel compilation in the Kotlin daemon may require more memory. To reduce memory consumption, increase
the heap size for the Kotlin daemon.
Learn more about the currently supported compiler options in the Kotlin Gradle plugin.
What's
new
in
Kotlin
1.6.0
Release date: 16 November 2021
Kotlin 1.6.0 introduces new language features, optimizations and improvements to existing features, and a lot of improvements to the
Kotlin standard library.
You can also find an overview of the changes in the release blog post.
Language
Kotlin 1.6.0 brings stabilization to several language features introduced for preview in the previous 1.5.30 release:
Stable exhaustive when statements for enum, sealed and Boolean subjects
It also includes various type inference improvements and support for annotations on class type parameters:
Stable
exhaustive
when
statements
for
enum,
sealed,
and
Boolean
subjects
An exhaustive when statement contains branches for all possible types or values of its subject, or for some types plus an else branch. It
covers all possible cases, making your code safer.
We will soon prohibit non-exhaustive when statements to make the behavior consistent with when expressions. To ensure smooth
migration, Kotlin 1.6.0 reports warnings about non-exhaustive when statements with an enum, sealed, or Boolean subject. These warnings
will become errors in future releases.
125
data class TextMessage(val number: String) : Contact()
}
See this YouTrack ticket for a more detailed explanation of the change and its effects.
Stable
suspending
functions
as
supertypes
Implementation of suspending functional types has become Stable in Kotlin 1.6.0. A preview was available in 1.5.30.
The feature can be useful when designing APIs that use Kotlin coroutines and accept suspending functional types. You can now
streamline your code by enclosing the desired behavior in a separate class that implements a suspending functional type.
You can use an instance of this class where only lambdas and suspending function references were allowed previously:
launchOnClick(MyClickAction()).
You can't mix ordinary functional types and suspending ones in the list of supertypes.
Stable
suspend
conversions
Kotlin 1.6.0 introduces Stable conversions from regular to suspending functional types. Starting from 1.4.0, the feature supported
functional literals and callable references. With 1.6.0, it works with any form of expression. As a call argument, you can now pass any
expression of a suitable regular functional type where suspending is expected. The compiler will perform an implicit conversion
automatically.
fun suspending() {}
126
getSuspending(::suspending) // OK
getSuspending(regular) // OK
}
Stable
instantiation
of
annotation
classes
Kotlin 1.5.30 introduced experimental support for instantiation of annotation classes on the JVM platform. With 1.6.0, the feature is
available by default both for Kotlin/JVM and Kotlin/JS.
Improved
type
inference
for
recursive
generic
types
Kotlin 1.5.30 introduced an improvement to type inference for recursive generic types, which allowed their type arguments to be inferred
based only on the upper bounds of the corresponding type parameters. The improvement was available with the compiler option. In
version 1.6.0 and later, it is enabled by default.
// Before 1.5.30
val containerA = PostgreSQLContainer<Nothing>(DockerImageName.parse("postgres:13-alpine")).apply {
withDatabaseName("db")
withUsername("user")
withPassword("password")
withInitScript("sql/schema.sql")
}
Changes
to
builder
inference
Builder inference is a type inference flavor which is useful when calling generic builder functions. It can infer the type arguments of a call
with the help of type information from calls inside its lambda argument.
We're making multiple changes that are bringing us closer to fully stable builder inference. Starting with 1.6.0:
You can make calls returning an instance of a not yet inferred type inside a builder lambda without specifying the -Xunrestricted-
builder-inference compiler option introduced in 1.5.30.
With -Xenable-builder-inference, you can write your own builders without applying the @BuilderInference annotation.
Note that clients of these builders will need to specify the same -Xenable-builder-inference compiler option.
With the -Xenable-builder-inference, builder inference automatically activates if a regular type inference cannot get enough information
about a type.
Support
for
annotations
on
class
type
parameters
Support for annotations on class type parameters looks like this:
127
@Target(AnnotationTarget.TYPE_PARAMETER)
annotation class BoxContent
Annotations on all type parameters are emitted into JVM bytecode so annotation processors are able to use them.
Supporting
previous
API
versions
for
a
longer
period
Starting with Kotlin 1.6.0, we will support development for three previous API versions instead of two, along with the current stable one.
Currently, we support versions 1.3, 1.4, 1.5, and 1.6.
Kotlin/JVM
For Kotlin/JVM, starting with 1.6.0, the compiler can generate classes with a bytecode version corresponding to JVM 17. The new
language version also includes optimized delegated properties and repeatable annotations, which we had on the roadmap:
Optimize delegated properties which call get/set on the given KProperty instance
Repeatable
annotations
with
runtime
retention
for
1.8
JVM
target
Java 8 introduced repeatable annotations, which can be applied multiple times to a single code element. The feature requires two
declarations to be present in the Java code: the repeatable annotation itself marked with @java.lang.annotation.Repeatable and the
containing annotation to hold its values.
Kotlin also has repeatable annotations, but requires only @kotlin.annotation.Repeatable to be present on an annotation declaration to
make it repeatable. Before 1.6.0, the feature supported only SOURCE retention and was incompatible with Java's repeatable annotations.
Kotlin 1.6.0 removes these limitations. @kotlin.annotation.Repeatable now accepts any retention and makes the annotation repeatable
both in Kotlin and Java. Java's repeatable annotations are now also supported from the Kotlin side.
While you can declare a containing annotation, it's not necessary. For example:
If an annotation @Tag is marked with @kotlin.annotation.Repeatable, the Kotlin compiler automatically generates a containing
annotation class under the name of @Tag.Container:
@Repeatable
annotation class Tag(val name: String)
To set a custom name for a containing annotation, apply the @kotlin.jvm.JvmRepeatable meta-annotation and pass the explicitly
declared containing annotation class as an argument:
@JvmRepeatable(Tags::class)
annotation class Tag(val name: String)
128
Kotlin reflection now supports both Kotlin's and Java's repeatable annotations via a new function, KAnnotatedElement.findAnnotations().
Optimize
delegated
properties
which
call
get/set
on
the
given
KProperty
instance
We optimized the generated JVM bytecode by omitting the $delegate field and generating immediate access to the referenced property.
class Box<T> {
private var impl: T = ...
Kotlin no longer generates the field content$delegate. Property accessors of the content variable invoke the impl variable directly, skipping
the delegated property's getValue/setValue operators and thus avoiding the need for the property reference object of the KProperty type.
Kotlin/Native
Kotlin/Native is receiving multiple improvements and component updates, some of them in the preview state:
Performance improvements
Preview
of
the
new
memory
manager
The new Kotlin/Native memory manager is Experimental. It may be dropped or changed at any time. Opt-in is required (see
details below), and you should use it only for evaluation purposes. We would appreciate your feedback on it in YouTrack.
With Kotlin 1.6.0, you can try the development preview of the new Kotlin/Native memory manager. It moves us closer to eliminating the
differences between the JVM and Native platforms to provide a consistent developer experience in multiplatform projects.
One of the notable changes is the lazy initialization of top-level properties, like in Kotlin/JVM. A top-level property gets initialized when a
top-level property or function from the same file is accessed for the first time. This mode also includes global interprocedural optimization
129
(enabled only for release binaries), which removes redundant initialization checks.
We've recently published a blog post about the new memory manager. Read it to learn about the current state of the new memory
manager and find some demo projects, or jump right to the migration instructions to try it yourself. Please check how the new memory
manager works on your projects and share feedback in our issue tracker, YouTrack.
Support
for
Xcode
13
Kotlin/Native 1.6.0 supports Xcode 13 – the latest version of Xcode. Feel free to update your Xcode and continue working on your Kotlin
projects for Apple operating systems.
New libraries added in Xcode 13 aren't available for use in Kotlin 1.6.0, but we're going to add support for them in upcoming
versions.
Compilation
of
Windows
targets
on
any
host
Starting from 1.6.0, you don't need a Windows host to compile the Windows targets mingwX64 and mingwX86. They can be compiled on
any host that supports Kotlin/Native.
LLVM
and
linker
updates
We've reworked the LLVM dependency that Kotlin/Native uses under the hood. This brings various benefits, including:
Decreased dependency size. For example, on macOS it's now about 300 MB instead of 1200 MB in the previous version.
Excluded dependency on the ncurses5 library that isn't available in modern Linux distributions.
In addition to the LLVM update, Kotlin/Native now uses the LLD linker (a linker from the LLVM project) for MingGW targets. It provides
various benefits over the previously used ld.bfd linker, and will allow us to improve runtime performance of produced binaries and support
compiler caches for MinGW targets. Note that LLD requires import libraries for DLL linkage. Learn more in this Stack Overflow thread.
Performance
improvements
Kotlin/Native 1.6.0 delivers the following performance improvements:
Compilation time: compiler caches are enabled by default for linuxX64 and iosArm64 targets. This speeds up most compilations in
debug mode (except the first one). Measurements showed about a 200% speed increase on our test projects. The compiler caches
have been available for these targets since Kotlin 1.5.0 with additional Gradle properties; you can remove them now.
Runtime: iterating over arrays with for loops is now up to 12% faster thanks to optimizations in the produced LLVM code.
Unified
compiler
plugin
ABI
with
JVM
and
JS
IR
backends
The option to use the common IR compiler plugin ABI for Kotlin/Native is Experimental. It may be dropped or changed at any
time. Opt-in is required (see details below), and you should use it only for evaluation purposes. We would appreciate your
feedback on it in YouTrack.
In previous versions, authors of compiler plugins had to provide separate artifacts for Kotlin/Native because of the differences in the ABI.
130
Starting from 1.6.0, the Kotlin Multiplatform Gradle plugin is able to use the embeddable compiler jar – the one used for the JVM and JS IR
backends – for Kotlin/Native. This is a step toward unification of the compiler plugin development experience, as you can now use the
same compiler plugin artifacts for Native and other supported platforms.
This is a preview version of such support, and it requires an opt-in. To start using generic compiler plugin artifacts for Kotlin/Native, add
the following line to gradle.properties: kotlin.native.useEmbeddableCompilerJar=true.
We're planning to use the embeddable compiler jar for Kotlin/Native by default in the future, so it's vital for us to hear how the preview
works for you.
If you are an author of a compiler plugin, please try this mode and check if it works for your plugin. Note that depending on your plugin's
structure, migration steps may be required. See this YouTrack issue for migration instructions and leave your feedback in the comments.
Detailed
error
messages
for
klib
linkage
failures
The Kotlin/Native compiler now provides detailed error messages for klib linkage errors. The messages now have clear error descriptions,
and they also include information about possible causes and ways to fix them.
For example:
1.5.30:
1.6.0:
This could happen if there are two libraries, where one library was compiled against the different version of
the other library than the one currently used in the project.
Please check that the project configuration is correct and has consistent versions of dependencies.
Project dependencies:
<dependencies tree>
Reworked
unhandled
exception
handling
API
We've unified the processing of unhandled exceptions throughout the Kotlin/Native runtime and exposed the default processing as the
function processUnhandledException(throwable: Throwable) for use by custom execution environments, like kotlinx.coroutines. This
processing is also applied to exceptions that escape operation in Worker.executeAfter(), but only for the new memory manager.
API improvements also affected the hooks that have been set by setUnhandledExceptionHook(). Previously such hooks were reset after
the Kotlin/Native runtime called the hook with an unhandled exception, and the program would always terminate right after. Now these
hooks may be used more than once, and if you want the program to always terminate on an unhandled exception, either do not set an
unhandled exception hook (setUnhandledExceptionHook()), or make sure to call terminateWithUnhandledException() at the end of your
hook. This will help you send exceptions to a third-party crash reporting service (like Firebase Crashlytics) and then terminate the program.
Exceptions that escape main() and exceptions that cross the interop boundary will always terminate the program, even if the hook did not
call terminateWithUnhandledException().
131
Kotlin/JS
We're continuing to work on stabilizing the IR backend for the Kotlin/JS compiler. Kotlin/JS now has an option to disable downloading of
Node.js and Yarn.
Option
to
use
pre-installed
Node.js
and
Yarn
You can now disable downloading Node.js and Yarn when building Kotlin/JS projects and use the instances already installed on the host.
This is useful for building on servers without internet connectivity, such as CI servers.
To disable downloading external components, add the following lines to your build.gradle(.kts):
Yarn:
Kotlin
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin> {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension>().download = false // or
true for default behavior
}
Groovy
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnPlugin) {
rootProject.extensions.getByType(org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension).download
= false
}
Node.js:
Kotlin
rootProject.plugins.withType<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin> {
rootProject.the<org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension>().download = false //
or true for default behavior
}
Groovy
rootProject.plugins.withType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin) {
rootProject.extensions.getByType(org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension).download
= false
}
Kotlin
Gradle
plugin
In Kotlin 1.6.0, we changed the deprecation level of the KotlinGradleSubplugin class to 'ERROR'. This class was used for writing compiler
plugins. In the following releases, we'll remove this class. Use the class KotlinCompilerPluginSupportPlugin instead.
132
We removed the kotlin.useFallbackCompilerSearch build option and the noReflect and includeRuntime compiler options. The useIR
compiler option has been hidden and will be removed in upcoming releases.
Learn more about the currently supported compiler options in the Kotlin Gradle plugin.
Standard
library
The new 1.6.0 version of the standard library stabilizes experimental features, introduces new ones, and unifies its behavior across the
platforms:
Stable typeOf()
Deprecations
New
readline
functions
Kotlin 1.6.0 offers new functions for handling standard input: readln() and readlnOrNull().
For now, new functions are available for the JVM and Native target platforms only.
readLine()!! readln() Reads a line from stdin and returns it, or throws a RuntimeException if EOF has been reached.
readLine() readlnOrNull() Reads a line from stdin and returns it, or returns null if EOF has been reached.
We believe that eliminating the need to use !! when reading a line will improve the experience for newcomers and simplify teaching Kotlin.
To make the read-line operation name consistent with its println() counterpart, we've decided to shorten the names of new functions to
'ln'.
fun main() {
133
//sampleStart
var sum = 0
while (true) {
val nextLine = readlnOrNull().takeUnless {
it.isNullOrEmpty()
} ?: break
sum += nextLine.toInt()
}
println(sum)
//sampleEnd
}
The existing readLine() function will get a lower priority than readln() and readlnOrNull() in your IDE code completion. IDE inspections will
also recommend using new functions instead of the legacy readLine().
Stable
typeOf()
Version 1.6.0 brings a Stable typeOf() function, closing one of the major roadmap items.
Since 1.3.40, typeOf() was available on the JVM platform as an experimental API. Now you can use it in any Kotlin platform and get KType
representation of any Kotlin type that the compiler can infer:
fun main() {
val fromExplicitType = typeOf<Int>()
val fromReifiedType = renderType<List<Int>>()
}
Stable
collection
builders
In Kotlin 1.6.0, collection builder functions have been promoted to Stable. Collections returned by collection builders are now serializable
in their read-only state.
You can now use buildMap(), buildList(), and buildSet() without the opt-in annotation:
fun main() {
//sampleStart
val x = listOf('b', 'c')
val y = buildList {
add('a')
addAll(x)
add('d')
}
println(y) // [a, b, c, d]
//sampleEnd
}
Stable
Duration
API
The Duration class for representing duration amounts in different time units has been promoted to Stable. In 1.6.0, the Duration API has
received the following changes:
The first component of the toComponents() function that decomposes the duration into days, hours, minutes, seconds, and
134
nanoseconds now has the Long type instead of Int. Before, if the value didn't fit into the Int range, it was coerced into that range. With
the Long type, you can decompose any value in the duration range without cutting off the values that don't fit into Int.
The DurationUnit enum is now standalone and not a type alias of java.util.concurrent.TimeUnit on the JVM. We haven't found any
convincing cases in which having typealias DurationUnit = TimeUnit could be useful. Also, exposing the TimeUnit API through a type
alias might confuse DurationUnit users.
In response to community feedback, we're bringing back extension properties like Int.seconds. But we'd like to limit their applicability,
so we put them into the companion of the Duration class. While the IDE can still propose extensions in completion and automatically
insert an import from the companion, in the future we plan to limit this behavior to cases when the Duration type is expected.
import kotlin.time.Duration.Companion.seconds
fun main() {
//sampleStart
val duration = 10000
println("There are ${duration.seconds.inWholeMinutes} minutes in $duration seconds")
// There are 166 minutes in 10000 seconds
//sampleEnd
}
We suggest replacing previously introduced companion functions, such as Duration.seconds(Int), and deprecated top-level extensions
like Int.seconds with new extensions in Duration.Companion.
Such a replacement may cause ambiguity between old top-level extensions and new companion extensions. Be sure to use
the wildcard import of the kotlin.time package – import kotlin.time.* – before doing automated migration.
Splitting
Regex
into
a
sequence
The Regex.splitToSequence(CharSequence) and CharSequence.splitToSequence(Regex) functions are promoted to Stable. They split the
string around matches of the given regex, but return the result as a Sequence so that all operations on this result are executed lazily:
fun main() {
//sampleStart
val colorsText = "green, red, brown&blue, orange, pink&green"
val regex = "[,\\s]+".toRegex()
val mixedColor = regex.splitToSequence(colorsText)
// or
// val mixedColor = colorsText.splitToSequence(regex)
.onEach { println(it) }
.firstOrNull { it.contains('&') }
println(mixedColor) // "brown&blue"
//sampleEnd
}
Bit
rotation
operations
on
integers
In Kotlin 1.6.0, the rotateLeft() and rotateRight() functions for bit manipulations became Stable. The functions rotate the binary
representation of the number left or right by a specified number of bits:
fun main() {
//sampleStart
val number: Short = 0b10001
println(number
.rotateRight(2)
.toString(radix = 2)) // 100000000000100
135
println(number
.rotateLeft(2)
.toString(radix = 2)) // 1000100
//sampleEnd
}
Changes
for
replace()
and
replaceFirst()
in
JS
Before Kotlin 1.6.0, the replace() and replaceFirst() Regex functions behaved differently in Java and JS when the replacement string
contained a group reference. To make the behavior consistent across all target platforms, we've changed their implementation in JS.
Occurrences of ${name} or $index in the replacement string are substituted with the subsequences corresponding to the captured groups
with the specified index or a name:
$index – the first digit after '$' is always treated as a part of the group reference. Subsequent digits are incorporated into the index only
if they form a valid group reference.Only digits '0'–'9' are considered potential components of the group reference. Note that indexes of
captured groups start from '1'. The group with index '0' stands for the whole match.
${name} – the name can consist of Latin letters 'a'–'z', 'A'–'Z', or digits '0'–'9'. The first character must be a letter.
Named groups in replacement patterns are currently supported only on the JVM.
To include the succeeding character as a literal in the replacement string, use the backslash character \:
fun main() {
//sampleStart
println(Regex("(.+)").replace("Kotlin", """\$ $1""")) // $ Kotlin
println(Regex("(.+)").replaceFirst("1.6.0", """\\ $1""")) // \ 1.6.0
//sampleEnd
}
You can use Regex.escapeReplacement() if the replacement string has to be treated as a literal string.
Improvements
to
the
existing
API
Version 1.6.0 added the infix extension function for Comparable.compareTo(). You can now use the infix form for comparing two
objects for order:
Regex.replace() in JS is now also not inline to unify its implementation across all platforms.
The compareTo() and equals() String functions, as well as the isBlank() CharSequence function now behave in JS exactly the same way
they do on the JVM. Previously there were deviations when it came to non-ASCII characters.
Deprecations
In Kotlin 1.6.0, we're starting the deprecation cycle with a warning for some JS-only stdlib API.
136
concat(), match(), and matches() string functions
To concatenate the string with the string representation of a given other object, use plus() instead of concat().
To find all occurrences of a regular expression within the input, use findAll() of the Regex class instead of String.match(regex: String).
To check if the regular expression matches the entire input, use matches() of the Regex class instead of String.matches(regex: String).
Tools
Kover
–
a
code
coverage
tool
for
Kotlin
The Kover Gradle plugin is Experimental. We would appreciate your feedback on it in GitHub.
With Kotlin 1.6.0, we're introducing Kover – a Gradle plugin for the IntelliJ and JaCoCo Kotlin code coverage agents. It works with all
language constructs, including inline functions.
Gif
Coroutines
1.6.0-RC
kotlinx.coroutines 1.6.0-RC is out with multiple features and improvements:
137
Support for the new Kotlin/Native memory manager
Introduction of dispatcher views API, which allows limiting parallelism without creating additional threads
Introduction of CopyableThreadContextElement, which gives coroutines a thread-safe write access to ThreadLocal variables
Migrating
to
Kotlin
1.6.0
IntelliJ IDEA and Android Studio will suggest updating the Kotlin plugin to 1.6.0 once it is available.
To migrate existing projects to Kotlin 1.6.0, change the Kotlin version to 1.6.0 and reimport your Gradle or Maven project. Learn how to
update to Kotlin 1.6.0.
To start a new project with Kotlin 1.6.0, update the Kotlin plugin and run the Project Wizard from File | New | Project.
The new command-line compiler is available for download on the GitHub release page.
Kotlin 1.6.0 is a feature release and can, therefore, bring changes that are incompatible with your code written for earlier versions of the
language. Find the detailed list of such changes in the Compatibility Guide for Kotlin 1.6.
What's
new
in
Kotlin
1.5.30
Release date: 24 August 2021
Kotlin 1.5.30 offers language updates including previews of future changes, various improvements in platform support and tooling, and
new standard library functions.
Language features, including experimental sealed when statements, changes in using opt-in requirement, and others
You can also find a short overview of the changes in the release blog post and this video:
138
Gif
Language
features
Kotlin 1.5.30 is presenting previews of future language changes and bringing improvements to the opt-in requirement mechanism and
type inference:
Exhaustive
when
statements
for
sealed
and
Boolean
subjects
Support for sealed (exhaustive) when statements is Experimental. It may be dropped or changed at any time. Opt-in is required
(see the details below), and you should use it only for evaluation purposes. We would appreciate your feedback on it in
YouTrack.
An exhaustive when statement contains branches for all possible types or values of its subject or for some types plus an else branch. In
other words, it covers all possible cases.
We're planning to prohibit non-exhaustive when statements soon to make the behavior consistent with when expressions. To ensure
smooth migration, you can configure the compiler to report warnings about non-exhaustive when statements with a sealed class or a
Boolean. Such warnings will appear by default in Kotlin 1.6 and will become errors later.
139
Enums already get a warning.
fun main() {
val x: Mode = Mode.ON
when (x) {
Mode.ON -> println("ON")
}
// WARNING: Non exhaustive 'when' statements on sealed classes/interfaces
// will be prohibited in 1.7, add an 'OFF' or 'else' branch instead
To enable this feature in Kotlin 1.5.30, use language version 1.6. You can also change the warnings to errors by enabling progressive
mode.
Kotlin
kotlin {
sourceSets.all {
languageSettings.apply {
languageVersion = "1.6"
//progressiveMode = true // false by default
}
}
}
Groovy
kotlin {
sourceSets.all {
languageSettings {
languageVersion = '1.6'
//progressiveMode = true // false by default
}
}
}
Suspending
functions
as
supertypes
Support for suspending functions as supertypes is Experimental. It may be dropped or changed at any time. Opt-in is required
(see the details below), and you should use it only for evaluation purposes. We would appreciate your feedback on it in
YouTrack.
140
Kotlin 1.5.30 provides a preview of the ability to use a suspend functional type as a supertype with some limitations.
Kotlin
kotlin {
sourceSets.all {
languageSettings.apply {
languageVersion = "1.6"
}
}
}
Groovy
kotlin {
sourceSets.all {
languageSettings {
languageVersion = '1.6'
}
}
}
You can't mix an ordinary functional type and a suspend functional type as supertype. This is because of the implementation details of
suspend functional types in the JVM backend. They are represented in it as ordinary functional types with a marker interface. Because
of the marker interface, there is no way to tell which of the superinterfaces are suspended and which are ordinary.
You can't use multiple suspend functional supertypes. If there are type checks, you also can't use multiple ordinary functional
supertypes.
Requiring
opt-in
on
implicit
usages
of
experimental
APIs
The opt-in requirement mechanism is Experimental. It may change at any time. See how to opt-in. Use it only for evaluation
purposes. We would appreciate your feedback on it in YouTrack.
The author of a library can mark an experimental API as requiring opt-in to inform users about its experimental state. The compiler raises a
warning or error when the API is used and requires explicit consent to suppress it.
In Kotlin 1.5.30, the compiler treats any declaration that has an experimental type in the signature as experimental. Namely, it requires
opt-in even for implicit usages of an experimental API. For example, if the function's return type is marked as an experimental API
element, a usage of the function requires you to opt-in even if the declaration is not marked as requiring an opt-in explicitly.
// Library code
141
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS)
annotation class MyDateTime // Opt-in requirement annotation
@MyDateTime
class DateProvider // A class requiring opt-in
// Client code
Changes
to
using
opt-in
requirement
annotations
with
different
targets
The opt-in requirement mechanism is Experimental. It may change at any time. See how to opt-in. Use it only for evaluation
purposes. We would appreciate your feedback on it in YouTrack.
Kotlin 1.5.30 presents new rules for using and declaring opt-in requirement annotations on different targets. The compiler now reports an
error for use cases that are impractical to handle at compile time. In Kotlin 1.5.30:
Marking local variables and value parameters with opt-in requirement annotations is forbidden at the use site.
Marking backing fields and getters is forbidden. You can mark the basic property instead.
Setting TYPE and TYPE_PARAMETER annotation targets is forbidden at the opt-in requirement annotation declaration site.
Improvements
to
type
inference
for
recursive
generic
types
In Kotlin and Java, you can define a recursive generic type, which references itself in its type parameters. In Kotlin 1.5.30, the Kotlin
compiler can infer a type argument based only on upper bounds of the corresponding type parameter if it is a recursive generic. This
makes it possible to create various patterns with recursive generic types that are often used in Java to make builder APIs.
// Kotlin 1.5.20
val containerA = PostgreSQLContainer<Nothing>(DockerImageName.parse("postgres:13-alpine")).apply {
withDatabaseName("db")
withUsername("user")
withPassword("password")
withInitScript("sql/schema.sql")
}
// Kotlin 1.5.30
val containerB = PostgreSQLContainer(DockerImageName.parse("postgres:13-alpine"))
.withDatabaseName("db")
.withUsername("user")
.withPassword("password")
.withInitScript("sql/schema.sql")
142
You can enable the improvements by passing the -Xself-upper-bound-inference or the -language-version 1.6 compiler options. See other
examples of newly supported use cases in this YouTrack ticket.
Eliminating
builder
inference
restrictions
Builder inference is a special kind of type inference that allows you to infer the type arguments of a call based on type information from
other calls inside its lambda argument. This can be useful when calling generic builder functions such as buildList() or sequence(): buildList
{ add("string") }.
Inside such a lambda argument, there was previously a limitation on using the type information that the builder inference tries to infer. This
means you can only specify it and cannot get it. For example, you cannot call get() inside a lambda argument of buildList() without
explicitly specified type arguments.
Kotlin 1.5.30 removes these limitations with the -Xunrestricted-builder-inference compiler option. Add this option to enable previously
prohibited calls inside a lambda argument of generic builder functions:
@kotlin.ExperimentalStdlibApi
val list = buildList {
add("a")
add("b")
set(1, null)
val x = get(1)
if (x != null) {
removeAt(1)
}
}
@kotlin.ExperimentalStdlibApi
val map = buildMap {
put("a", 1)
put("b", 1.1)
put("c", 2f)
}
Also, you can enable this feature with the -language-version 1.6 compiler option.
Kotlin/JVM
With Kotlin 1.5.30, Kotlin/JVM receives the following features:
See the Gradle section for Kotlin Gradle plugin updates on the JVM platform.
Instantiation
of
annotation
classes
Instantiation of annotation classes is Experimental. It may be dropped or changed at any time. Opt-in is required (see the details
below), and you should use it only for evaluation purposes. We would appreciate your feedback on it in YouTrack.
With Kotlin 1.5.30 you can now call constructors of annotation classes in arbitrary code to obtain a resulting instance. This feature covers
the same use cases as the Java convention that allows the implementation of an annotation interface.
143
annotation class InfoMarker(val info: String)
Use the -language-version 1.6 compiler option to enable this feature. Note that all current annotation class limitations, such as restrictions
to define non-val parameters or members different from secondary constructors, remain intact.
Improved
nullability
annotation
support
configuration
The Kotlin compiler can read various types of nullability annotations to get nullability information from Java. This information allows it to
report nullability mismatches in Kotlin when calling Java code.
In Kotlin 1.5.30, you can specify whether the compiler reports a nullability mismatch based on the information from specific types of
nullability annotations. Just use the compiler option -Xnullability-annotations=@<package-name>:<report-level>. In the argument, specify
the fully qualified nullability annotations package and one of these report levels:
See the full list of supported nullability annotations along with their fully qualified package names.
Here is an example showing how to enable error reporting for the newly supported RxJava 3 nullability annotations: -Xnullability-
[email protected]:strict. Note that all such nullability mismatches are warnings by default.
Kotlin/Native
Kotlin/Native has received various changes and improvements:
Deprecation of linkage against DLLs without import libraries for MinGW targets
Apple
silicon
support
Kotlin 1.5.30 introduces native support for Apple silicon.
Previously, the Kotlin/Native compiler and tooling required the Rosetta translation environment for working on Apple silicon hosts. In Kotlin
1.5.30, the translation environment is no longer needed – the compiler and tooling can run on Apple silicon hardware without requiring any
additional actions.
144
We've also introduced new targets that make Kotlin code run natively on Apple silicon:
macosArm64
iosSimulatorArm64
watchosSimulatorArm64
tvosSimulatorArm64
They are available on both Intel-based and Apple silicon hosts. All existing targets are available on Apple silicon hosts as well.
Note that in 1.5.30 we provide only basic support for Apple silicon targets in the kotlin-multiplatform Gradle plugin. Particularly, the new
simulator targets aren't included in the ios, tvos, and watchos target shortcuts. Learn how to use Apple silicon targets with the target
shortcuts. We will keep working to improve the user experience with the new targets.
Improved
Kotlin
DSL
for
the
CocoaPods
Gradle
plugin
To use the new DSL, update your project to Kotlin 1.5.30, and specify the parameters in the cocoapods section of your build.gradle(.kts)
file:
cocoapods {
frameworkName = "MyFramework" // This property is deprecated
// and will be removed in future versions
// New DSL for framework configuration:
framework {
// All Framework properties are supported
// Framework name configuration. Use this property instead of
// deprecated 'frameworkName'
baseName = "MyFramework"
// Dynamic framework support
isStatic = false
// Dependency export
export(project(":anotherKMMModule"))
transitiveExport = false // This is default.
// Bitcode embedding
embedBitcode(BITCODE)
}
}
To specify a custom name, use the xcodeConfigurationToNativeBuildType parameter in the cocoapods section of your build.gradle(.kts)
file:
145
cocoapods {
// Maps custom Xcode configuration to NativeBuildType
xcodeConfigurationToNativeBuildType["CUSTOM_DEBUG"] = NativeBuildType.DEBUG
xcodeConfigurationToNativeBuildType["CUSTOM_RELEASE"] = NativeBuildType.RELEASE
}
This parameter will not appear in the Podspec file. When Xcode runs the Gradle build process, the Kotlin CocoaPods Gradle plugin will
select the necessary native build type.
There's no need to declare the Debug and Release configurations because they are supported by default.
Experimental
interoperability
with
Swift
5.5
async/await
Concurrency interoperability with Swift async/await is Experimental. It may be dropped or changed at any time. You should use
it only for evaluation purposes. We would appreciate your feedback on it in YouTrack.
We added support for calling Kotlin's suspending functions from Objective-C and Swift in 1.4.0, and now we're improving it to keep up
with a new Swift 5.5 feature – concurrency with async and await modifiers.
The Kotlin/Native compiler now emits the _Nullable_result attribute in the generated Objective-C headers for suspending functions with
nullable return types. This makes it possible to call them from Swift as async functions with the proper nullability.
Note that this feature is experimental and can be affected in the future by changes in both Kotlin and Swift. For now, we're offering a
preview of this feature that has certain limitations, and we are eager to hear what you think. Learn more about its current state and leave
your feedback in this YouTrack issue.
Improved
Swift/Objective-C
mapping
for
objects
and
companion
objects
Getting objects and companion objects can now be done in a way that is more intuitive for native iOS developers. For example, if you have
the following objects in Kotlin:
object MyObject {
val x = "Some value"
}
class MyClass {
companion object {
val x = "Some value"
}
}
To access them in Swift, you can use the shared and companion properties:
MyObject.shared
MyObject.shared.x
MyClass.companion
MyClass.Companion.shared
146
Deprecation
of
linkage
against
DLLs
without
import
libraries
for
MinGW
targets
LLD is a linker from the LLVM project, which we plan to start using in Kotlin/Native for MinGW targets because of its benefits over the
default ld.bfd – primarily its better performance.
However, the latest stable version of LLD doesn't support direct linkage against DLL for MinGW (Windows) targets. Such linkage requires
using import libraries. Although they aren't needed with Kotlin/Native 1.5.30, we're adding a warning to inform you that such usage is
incompatible with LLD that will become the default linker for MinGW in the future.
Please share your thoughts and concerns about the transition to the LLD linker in this YouTrack issue.
Kotlin
Multiplatform
1.5.30 brings the following notable updates to Kotlin Multiplatform:
Ability
to
use
custom
cinterop
libraries
in
shared
native
code
Kotlin Multiplatform gives you an option to use platform-dependent interop libraries in shared source sets. Before 1.5.30, this worked only
with platform libraries shipped with Kotlin/Native distribution. Starting from 1.5.30, you can use it with your custom cinterop libraries. To
enable this feature, add the kotlin.mpp.enableCInteropCommonization=true property in your gradle.properties:
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false
kotlin.mpp.enableCInteropCommonization=true
Support
for
XCFrameworks
All Kotlin Multiplatform projects can now have XCFrameworks as an output format. Apple introduced XCFrameworks as a replacement for
universal (fat) frameworks. With the help of XCFrameworks you:
Can gather logic for all the target platforms and architectures in a single bundle.
Don't need to remove all unnecessary architectures before publishing the application to the App Store.
XCFrameworks is useful if you want to use your Kotlin framework for devices and simulators on Apple M1.
Kotlin
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
plugins {
kotlin("multiplatform")
}
kotlin {
val xcf = XCFramework()
ios {
binaries.framework {
147
baseName = "shared"
xcf.add(this)
}
}
watchos {
binaries.framework {
baseName = "shared"
xcf.add(this)
}
}
tvos {
binaries.framework {
baseName = "shared"
xcf.add(this)
}
}
}
Groovy
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkConfig
plugins {
id 'org.jetbrains.kotlin.multiplatform'
}
kotlin {
def xcf = new XCFrameworkConfig(project)
ios {
binaries.framework {
baseName = "shared"
xcf.add(it)
}
}
watchos {
binaries.framework {
baseName = "shared"
xcf.add(it)
}
}
tvos {
binaries.framework {
baseName = "shared"
xcf.add(it)
}
}
}
When you declare XCFrameworks, these new Gradle tasks will be registered:
assembleXCFramework
assembleReleaseXCFramework
New
default
publishing
setup
for
Android
artifacts
Using the maven-publish Gradle plugin, you can publish your multiplatform library for the Android target by specifying Android variant
names in the build script. The Kotlin Gradle plugin will generate publications automatically.
148
Before 1.5.30, the generated publication metadata included the build type attributes for every published Android variant, making it
compatible only with the same build type used by the library consumer. Kotlin 1.5.30 introduces a new default publishing setup:
If all Android variants that the project publishes have the same build type attribute, then the published variants won't have the build
type attribute and will be compatible with any build type.
If the published variants have different build type attributes, then only those with the release value will be published without the build
type attribute. This makes the release variants compatible with any build type on the consumer side, while non-release variants will only
be compatible with the matching consumer build types.
To opt-out and keep the build type attributes for all variants, you can set this Gradle property: kotlin.android.buildTypeAttribute.keep=true.
Kotlin/JS
Two major improvements are coming to Kotlin/JS with 1.5.30:
JS
IR
compiler
backend
reaches
Beta
The IR-based compiler backend for Kotlin/JS, which was introduced in 1.4.0 in Alpha, has reached Beta.
Previously, we published the migration guide for the JS IR backend to help you migrate your projects to the new backend. Now we would
like to present the Kotlin/JS Inspection Pack IDE plugin, which displays the required changes directly in IntelliJ IDEA.
Better
debugging
experience
for
applications
with
the
Kotlin/JS
IR
backend
Kotlin 1.5.30 brings JavaScript source map generation for the Kotlin/JS IR backend. This will improve the Kotlin/JS debugging experience
when the IR backend is enabled, with full debugging support that includes breakpoints, stepping, and readable stack traces with proper
source references.
Gradle
As a part of our mission to improve the Kotlin Gradle plugin user experience, we've implemented the following features:
Support for Java toolchains, which includes an ability to specify a JDK home with the UsesKotlinJavaToolchain interface for older
Gradle versions
Support
for
Java
toolchains
Gradle 6.7 introduced the "Java toolchains support" feature. Using this feature, you can:
Run compilations, tests, and executables using JDKs and JREs that are different from the Gradle ones.
With toolchains support, Gradle can autodetect local JDKs and install missing JDKs that Gradle requires for the build. Now Gradle itself
can run on any JDK and still reuse the build cache feature.
149
The Kotlin Gradle plugin supports Java toolchains for Kotlin/JVM compilation tasks. A Java toolchain:
The ability to set the jdkHome option directly has been deprecated.
Sets the kotlinOptions.jvmTarget to the toolchain's JDK version if the user didn't set the jvmTarget option explicitly. If the toolchain is
not configured, the jvmTarget field uses the default value. Learn more about JVM target compatibility.
Use the following code to set a toolchain. Replace the placeholder <MAJOR_JDK_VERSION> with the JDK version you would like to use:
Kotlin
kotlin {
jvmToolchain {
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)) // "8"
}
}
Groovy
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)) // "8"
}
}
Note that setting a toolchain via the kotlin extension will update the toolchain for Java compile tasks as well.
You can set a toolchain via the java extension, and Kotlin compilation tasks will use it:
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)) // "8"
}
}
For information about setting any JDK version for KotlinCompile tasks, look through the docs about setting the JDK version with the Task
DSL.
For Gradle versions from 6.1 to 6.6, use the UsesKotlinJavaToolchain interface to set the JDK home.
Ability
to
specify
JDK
home
with
UsesKotlinJavaToolchain
interface
All Kotlin tasks that support setting the JDK via kotlinOptions now implement the UsesKotlinJavaToolchain interface. To set the JDK
home, put a path to your JDK and replace the <JDK_VERSION> placeholder:
Kotlin
project.tasks
150
.withType<UsesKotlinJavaToolchain>()
.configureEach {
it.kotlinJavaToolchain.jdk.use(
"/path/to/local/jdk",
JavaVersion.<LOCAL_JDK_VERSION>
)
}
Groovy
project.tasks
.withType(UsesKotlinJavaToolchain.class)
.configureEach {
it.kotlinJavaToolchain.jdk.use(
'/path/to/local/jdk',
JavaVersion.<LOCAL_JDK_VERSION>
)
}
Use the UsesKotlinJavaToolchain interface for Gradle versions from 6.1 to 6.6. Starting from Gradle 6.7, use the Java toolchains instead.
When using this feature, note that kapt task workers will only use process isolation mode, and the kapt.workers.isolation property will be
ignored.
Easier
way
to
explicitly
specify
Kotlin
daemon
JVM
arguments
In Kotlin 1.5.30, there's a new logic for the Kotlin daemon's JVM arguments. Each of the options in the following list overrides the ones
that came before it:
If nothing is specified, the Kotlin daemon inherits arguments from the Gradle daemon (as before). For example, in the gradle.properties
file:
org.gradle.jvmargs=-Xmx1500m -Xms=500m
If the Gradle daemon's JVM arguments have the kotlin.daemon.jvm.options system property, use it as before:
org.gradle.jvmargs=-Dkotlin.daemon.jvm.options=-Xmx1500m -Xms=500m
kotlin.daemon.jvmargs=-Xmx1500m -Xms=500m
Kotlin
kotlin {
kotlinDaemonJvmArgs = listOf("-Xmx486m", "-Xms256m", "-XX:+UseParallelGC")
}
Groovy
kotlin {
151
kotlinDaemonJvmArgs = ["-Xmx486m", "-Xms256m", "-XX:+UseParallelGC"]
}
Kotlin
tasks
.matching { it.name == "compileKotlin" && it is CompileUsingKotlinDaemon }
.configureEach {
(this as CompileUsingKotlinDaemon).kotlinDaemonJvmArguments.set(listOf("-Xmx486m", "-Xms256m", "-
XX:+UseParallelGC"))
}
Groovy
tasks
.matching {
it.name == "compileKotlin" && it instanceof CompileUsingKotlinDaemon
}
.configureEach {
kotlinDaemonJvmArguments.set(["-Xmx1g", "-Xms512m"])
}
In this case a new Kotlin daemon instance can start on task execution. Learn more about the Kotlin daemon's interactions
with JVM arguments.
For more information about the Kotlin daemon, see the Kotlin daemon and using it with Gradle.
Standard
library
Kotlin 1.5.30 is bringing improvements to the standard library's Duration and Regex APIs:
Changing
Duration.toString()
output
The Duration API is Experimental. It may be dropped or changed at any time. Use it only for evaluation purposes. We would
appreciate hearing your feedback on it in YouTrack.
Before Kotlin 1.5.30, the Duration.toString() function would return a string representation of its argument expressed in the unit that yielded
the most compact and readable number value. From now on, it will return a string value expressed as a combination of numeric
152
components, each in its own unit. Each component is a number followed by the unit's abbreviated name: d, h, m, s. For example:
The way negative durations are represented has also been changed. A negative duration is prefixed with a minus sign (-), and if it consists
of multiple components, it is surrounded with parentheses: -12m and -(1h 30m).
Note that small durations of less than one second are represented as a single number with one of the subsecond units. For example, ms
(milliseconds), us (microseconds), or ns (nanoseconds): 140.884ms, 500us, 24ns. Scientific notation is no longer used to represent them.
If you want to express duration in a single unit, use the overloaded Duration.toString(unit, decimals) function.
We recommend using Duration.toIsoString() in certain cases, including serialization and interchange. Duration.toIsoString() uses
the stricter ISO-8601 format instead of Duration.toString().
Parsing
Duration
from
String
The Duration API is Experimental. It may be dropped or changed at any time. Use it only for evaluation purposes. We would
appreciate hearing your feedback on it in this issue.
toString().
toString(unit, decimals).
153
toIsoString().
parseOrNull() and parseIsoStringOrNull(), which behave like the functions above but return null instead of throwing
IllegalArgumentException on invalid duration formats.
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
@ExperimentalTime
fun main() {
//sampleStart
val isoFormatString = "PT1H30M"
val defaultFormatString = "1h 30m"
val singleUnitFormatString = "1.5h"
val invalidFormatString = "1 hour 30 minutes"
println(Duration.parse(isoFormatString)) // "1h 30m"
println(Duration.parse(defaultFormatString)) // "1h 30m"
println(Duration.parse(singleUnitFormatString)) // "1h 30m"
//println(Duration.parse(invalidFormatString)) // throws exception
println(Duration.parseOrNull(invalidFormatString)) // "null"
//sampleEnd
}
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
@ExperimentalTime
fun main() {
//sampleStart
val isoFormatString = "PT1H30M"
val defaultFormatString = "1h 30m"
println(Duration.parseIsoString(isoFormatString)) // "1h 30m"
//println(Duration.parseIsoString(defaultFormatString)) // throws exception
println(Duration.parseIsoStringOrNull(defaultFormatString)) // "null"
//sampleEnd
}
Matching
with
Regex
at
a
particular
position
Regex.matchAt() and Regex.matchesAt() functions are Experimental. They may be dropped or changed at any time. Use them
only for evaluation purposes. We would appreciate hearing your feedback on them in YouTrack.
The new Regex.matchAt() and Regex.matchesAt() functions provide a way to check whether a regex has an exact match at a particular
position in a String or CharSequence.
fun main(){
//sampleStart
val releaseText = "Kotlin 1.5.30 is released!"
// regular expression: one digit, dot, one digit, dot, one or more digits
154
val versionRegex = "\\d[.]\\d[.]\\d+".toRegex()
println(versionRegex.matchesAt(releaseText, 0)) // "false"
println(versionRegex.matchesAt(releaseText, 7)) // "true"
//sampleEnd
}
fun main(){
//sampleStart
val releaseText = "Kotlin 1.5.30 is released!"
val versionRegex = "\\d[.]\\d[.]\\d+".toRegex()
println(versionRegex.matchAt(releaseText, 0)) // "null"
println(versionRegex.matchAt(releaseText, 7)?.value) // "1.5.30"
//sampleEnd
}
Splitting
Regex
to
a
sequence
The new Regex.splitToSequence() function is a lazy counterpart of split(). It splits the string around matches of the given regex, but it
returns the result as a Sequence so that all operations on this result are executed lazily.
fun main(){
//sampleStart
val colorsText = "green, red , brown&blue, orange, pink&green"
val regex = "[,\\s]+".toRegex()
val mixedColor = regex.splitToSequence(colorsText)
.onEach { println(it) }
.firstOrNull { it.contains('&') }
println(mixedColor) // "brown&blue"
//sampleEnd
}
Serialization
1.3.0-RC
kotlinx.serialization 1.3.0-RC is here with new JSON serialization capabilities:
155
What's
new
in
Kotlin
1.5.20
Release date: 24 June 2021
Kotlin 1.5.20 has fixes for issues discovered in the new features of 1.5.0, and it also includes various tooling improvements.
You can find an overview of the changes in the release blog post and this video:
Gif
Kotlin/JVM
Kotlin 1.5.20 is receiving the following updates on the JVM platform:
Support for calling Java's Lombok-generated methods within modules that have Kotlin and Java code
String
concatenation
via
invokedynamic
Kotlin 1.5.20 compiles string concatenations into dynamic invocations (invokedynamic) on JVM 9+ targets, thereby keeping up with
modern Java versions. More precisely, it uses StringConcatFactory.makeConcatWithConstants() for string concatenation.
To switch back to concatenation via StringBuilder.append() used in previous versions, add the compiler option -Xstring-concat=inline.
Learn how to add compiler options in Gradle, Maven, and the command-line compiler.
Support
for
JSpecify
nullness
annotations
The Kotlin compiler can read various types of nullability annotations to pass nullability information from Java to Kotlin. Version 1.5.20
introduces support for the JSpecify project, which includes the standard unified set of Java nullness annotations.
With JSpecify, you can provide more detailed nullability information to help Kotlin keep null-safety interoperating with Java. You can set
default nullability for the declaration, package, or module scope, specify parametric nullability, and more. You can find more details about
156
this in the JSpecify user guide.
// JavaClass.java
import *;
@NullMarked
public class JavaClass {
public String notNullableString() { return ""; }
public @Nullable String nullableString() { return ""; }
}
// Test.kt
fun kotlinFun() = with(JavaClass()) {
notNullableString().length // OK
nullableString().length // Warning: receiver nullability mismatch
}
In 1.5.20, all nullability mismatches according to the JSpecify-provided nullability information are reported as warnings. Use the -Xjspecify-
annotations=strict and -Xtype-enhancement-improvements-strict-mode compiler options to enable strict mode (with error reporting) when
working with JSpecify. Please note that the JSpecify project is under active development. Its API and implementation can change
significantly at any time.
Support
for
calling
Java's
Lombok-generated
methods
within
modules
that
have
Kotlin
and
Java
code
The Lombok compiler plugin is Experimental. It may be dropped or changed at any time. Use it only for evaluation purposes. We
would appreciate your feedback on it in YouTrack.
Kotlin 1.5.20 introduces an experimental Lombok compiler plugin. This plugin makes it possible to generate and use Java's Lombok
declarations within modules that have Kotlin and Java code. Lombok annotations work only in Java sources and are ignored if you use
them in Kotlin code.
@Getter, @Setter
@Data
@With
@Value
We're continuing to work on this plugin. To find out the detailed current state, visit the Lombok compiler plugin's README.
Currently, we don't have plans to support the @Builder annotation. However, we can consider this if you vote for @Builder in YouTrack.
157
Kotlin/Native
Kotlin/Native 1.5.20 offers a preview of the new feature and the tooling improvements:
Opt-in
export
of
KDoc
comments
to
generated
Objective-C
headers
The ability to export KDoc comments to generated Objective-C headers is Experimental. It may be dropped or changed at any
time. Opt-in is required (see the details below), and you should use it only for evaluation purposes. We would appreciate your
feedback on it in YouTrack.
You can now set the Kotlin/Native compiler to export the documentation comments (KDoc) from Kotlin code to the Objective-C
frameworks generated from it, making them visible to the frameworks' consumers.
/**
* Prints the sum of the arguments.
* Properly handles the case when the sum doesn't fit in 32-bit integer.
*/
fun printSum(a: Int, b: Int) = println(a.toLong() + b)
/**
* Prints the sum of the arguments.
* Properly handles the case when the sum doesn't fit in 32-bit integer.
*/
+ (void)printSumA:(int32_t)a b:(int32_t)b __attribute__((swift_name("printSum(a:b:)")));
To try out this ability to export KDoc comments to Objective-C headers, use the -Xexport-kdoc compiler option. Add the following lines to
build.gradle(.kts) of the Gradle projects you want to export comments from:
Kotlin
kotlin {
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
compilations.get("main").kotlinOptions.freeCompilerArgs += "-Xexport-kdoc"
}
}
Groovy
kotlin {
targets.withType(org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget) {
compilations.get("main").kotlinOptions.freeCompilerArgs += "-Xexport-kdoc"
158
}
}
We would be very grateful if you would share your feedback with us using this YouTrack ticket.
Compiler
bug
fixes
The Kotlin/Native compiler has received multiple bug fixes in 1.5.20. You can find the complete list in the changelog.
There is an important bug fix that affects compatibility: in previous versions, string constants that contained incorrect UTF surrogate pairs
were losing their values during compilation. Now such values are preserved. Application developers can safely update to 1.5.20 – nothing
will break. However, libraries compiled with 1.5.20 are incompatible with earlier compiler versions. See this YouTrack issue for details.
Improved
performance
of
Array.copyInto()
inside
one
array
We've improved the way Array.copyInto() works when its source and destination are the same array. Now such operations finish up to 20
times faster (depending on the number of objects being copied) due to memory management optimizations for this use case.
Kotlin/JS
With 1.5.20, we're publishing a guide that will help you migrate your projects to the new IR-based backend for Kotlin/JS.
Migration
guide
for
the
JS
IR
backend
The new migration guide for the JS IR backend identifies issues you may encounter during migration and provides solutions for them. If
you find any issues that aren't covered in the guide, please report them to our issue tracker.
Gradle
Kotlin 1.5.20 introduces the following features that can improve the Gradle experience:
Caching
for
annotation
processors'
classloaders
in
kapt
Caching for annotation processors' classloaders in kapt is Experimental. It may be dropped or changed at any time. Use it only
for evaluation purposes. We would appreciate your feedback on it in YouTrack.
There is now a new experimental feature that makes it possible to cache the classloaders of annotation processors in kapt. This feature
can increase the speed of kapt for consecutive Gradle runs.
To enable this feature, use the following properties in your gradle.properties file:
159
# disable for caching to work
kapt.include.compile.classpath=false
Deprecation
of
the
kotlin.parallel.tasks.in.project
build
property
With this release, Kotlin parallel compilation is controlled by the Gradle parallel execution flag --parallel. Using this flag, Gradle executes
tasks concurrently, increasing the speed of compiling tasks and utilizing the resources more efficiently.
You no longer need to use the kotlin.parallel.tasks.in.project property. This property has been deprecated and will be removed in the next
major release.
Standard
library
Kotlin 1.5.20 changes the platform-specific implementations of several functions for working with characters and as a result brings
unification across platforms:
Support for all Unicode digits in Char.digitToInt() for Kotlin/Native and Kotlin/JS.
Support
for
all
Unicode
digits
in
Char.digitToInt()
in
Kotlin/Native
and
Kotlin/JS
Char.digitToInt() returns the numeric value of the decimal digit that the character represents. Before 1.5.20, the function supported all
Unicode digit characters only for Kotlin/JVM: implementations on the Native and JS platforms supported only ASCII digits.
From now, both with Kotlin/Native and Kotlin/JS, you can call Char.digitToInt() on any Unicode digit character and get its numeric
representation.
fun main() {
//sampleStart
val ten = '\u0661'.digitToInt() + '\u0039'.digitToInt() // ARABIC-INDIC DIGIT ONE + DIGIT NINE
println(ten)
//sampleEnd
}
Unification
of
Char.isLowerCase()/isUpperCase()
implementations
across
platforms
The functions Char.isUpperCase() and Char.isLowerCase() return a boolean value depending on the case of the character. For Kotlin/JVM,
the implementation checks both the General_Category and the Other_Uppercase/Other_Lowercase Unicode properties.
Prior to 1.5.20, implementations for other platforms worked differently and considered only the general category. In 1.5.20,
implementations are unified across platforms and use both properties to determine the character case:
fun main() {
//sampleStart
val latinCapitalA = 'A' // has "Lu" general category
val circledLatinCapitalA = 'Ⓐ' // has "Other_Uppercase" property
println(latinCapitalA.isUpperCase() && circledLatinCapitalA.isUpperCase())
//sampleEnd
}
160
What's
new
in
Kotlin
1.5.0
Release date: 5 May 2021
Kotlin 1.5.0 introduces new language features, stable IR-based JVM compiler backend, performance improvements, and evolutionary
changes such as stabilizing experimental features and deprecating outdated ones.
You can also find an overview of the changes in the release blog post.
Language
features
Kotlin 1.5.0 brings stable versions of the new language features presented for preview in 1.4.30:
Inline classes
Detailed descriptions of these features are available in this blog post and the corresponding pages of Kotlin documentation.
JVM
records
support
Java is evolving fast, and to make sure Kotlin remains interoperable with it, we've introduced support for one of its latest features – record
classes.
In Kotlin code, you can use Java record classes like you would use typical classes with properties.
To use a Kotlin class as a record in Java code, make it a data class and mark it with the @JvmRecord annotation.
@JvmRecord
data class User(val name: String, val age: Int)
Gif
161
Watch video online.
Sealed
interfaces
Kotlin interfaces can now have the sealed modifier, which works on interfaces in the same way it works on classes: all implementations of
a sealed interface are known at compile time.
You can rely on that fact, for example, to write exhaustive when expressions.
Additionally, sealed interfaces enable more flexible restricted class hierarchies because a class can directly inherit more than one sealed
interface.
Gif
Package-wide
sealed
class
hierarchies
Sealed classes can now have subclasses in all files of the same compilation unit and the same package. Previously, all subclasses had to
appear in the same file.
Direct subclasses may be top-level or nested inside any number of other named classes, named interfaces, or named objects.
The subclasses of a sealed class must have a name that is properly qualified – they cannot be local or anonymous objects.
162
Learn more about sealed class hierarchies.
Inline
classes
Inline classes are a subset of value-based classes that only hold values. You can use them as wrappers for a value of a certain type
without the additional overhead that comes from using memory allocations.
Inline classes can be declared with the value modifier before the name of the class:
@JvmInline
value class Password(val s: String)
Gif
Kotlin/JVM
Kotlin/JVM has received a number of improvements, both internal and user-facing. Here are the most notable among them:
163
Improvements to handling nullability annotations
Stable
JVM
IR
backend
The IR-based backend for the Kotlin/JVM compiler is now Stable and enabled by default.
Starting from Kotlin 1.4.0, early versions of the IR-based backend were available for preview, and it has now become the default for
language version 1.5. The old backend is still used by default for earlier language versions.
You can find more details about the benefits of the IR backend and its future development in this blog post.
If you need to use the old backend in Kotlin 1.5.0, you can add the following lines to the project's configuration file:
In Gradle:
Kotlin
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
kotlinOptions.useOldBackend = true
}
Groovy
tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile) {
kotlinOptions.useOldBackend = true
}
In Maven:
<configuration>
<args>
<arg>-Xuse-old-backend</arg>
</args>
</configuration>
New
default
JVM
target:
1.8
The default target version for Kotlin/JVM compilations is now 1.8. The 1.6 target is deprecated.
If you need a build for JVM 1.6, you can still switch to this target. Learn how:
in Gradle
in Maven
SAM
adapters
via
invokedynamic
Kotlin 1.5.0 now uses dynamic invocations (invokedynamic) for compiling SAM (Single Abstract Method) conversions:
164
The new implementation uses LambdaMetafactory.metafactory() and auxiliary wrapper classes are no longer generated during
compilation. This decreases the size of the application's JAR, which improves the JVM startup performance.
To roll back to the old implementation scheme based on anonymous class generation, add the compiler option -Xsam-conversions=class.
Learn how to add compiler options in Gradle, Maven, and the command-line compiler.
Lambdas
via
invokedynamic
Compiling plain Kotlin lambdas into invokedynamic is Experimental. It may be dropped or changed at any time. Opt-in is
required (see details below), and you should use it only for evaluation purposes. We would appreciate hearing your feedback on
it in YouTrack.
Kotlin 1.5.0 is introducing experimental support for compiling plain Kotlin lambdas (which are not converted to an instance of a functional
interface) into dynamic invocations (invokedynamic). The implementation produces lighter binaries by using
LambdaMetafactory.metafactory(), which effectively generates the necessary classes at runtime. Currently, it has three limitations
compared to ordinary lambda compilation:
Experimental reflect API does not support lambdas created with LambdaMetafactory.
To try this feature, add the -Xlambdas=indy compiler option. We would be grateful if you could share your feedback on it using this
YouTrack ticket.
Learn how to add compiler options in Gradle, Maven, and command-line compiler.
Deprecation
of
@JvmDefault
and
old
Xjvm-default
modes
Prior to Kotlin 1.4.0, there was the @JvmDefault annotation along with -Xjvm-default=enable and -Xjvm-default=compatibility modes. They
served to create the JVM default method for any particular non-abstract member in the Kotlin interface.
In Kotlin 1.4.0, we introduced the new Xjvm-default modes, which switch on default method generation for the whole project.
In Kotlin 1.5.0, we are deprecating @JvmDefault and the old Xjvm-default modes: -Xjvm-default=enable and -Xjvm-default=compatibility.
Improvements
to
handling
nullability
annotations
Kotlin supports handling type nullability information from Java with nullability annotations. Kotlin 1.5.0 introduces a number of
improvements for the feature:
It reads nullability annotations on type arguments in compiled Java libraries that are used as dependencies.
Arrays
Varargs
Fields
165
Type parameters and their bounds
If a nullability annotation has multiple targets applicable to a type, and one of these targets is TYPE_USE, then TYPE_USE is preferred.
For example, the method signature @Nullable String[] f() becomes fun f(): Array<String?>! if @Nullable supports both TYPE_USE and
METHODas targets.
For these newly supported cases, using the wrong type nullability when calling Java from Kotlin produces warnings. Use the -Xtype-
enhancement-improvements-strict-mode compiler option to enable strict mode for these cases (with error reporting).
Kotlin/Native
Kotlin/Native is now more performant and stable. The notable changes are:
Performance improvements
Performance
improvements
In 1.5.0, Kotlin/Native is receiving a set of performance improvements that speed up both compilation and execution.
Compiler caches are now supported in debug mode for linuxX64 (only on Linux hosts) and iosArm64 targets. With compiler caches
enabled, most debug compilations complete much faster, except for the first one. Measurements showed about a 200% speed increase
on our test projects.
To use compiler caches for new targets, opt in by adding the following lines to the project's gradle.properties:
If you encounter any issues after enabling the compiler caches, please report them to our issue tracker YouTrack.
Deactivation
of
the
memory
leak
checker
The built-in Kotlin/Native memory leak checker has been disabled by default.
It was initially designed for internal use, and it is able to find leaks only in a limited number of cases, not all of them. Moreover, it later
turned out to have issues that can cause application crashes. So we've decided to turn off the memory leak checker.
The memory leak checker can still be useful for certain cases, for example, unit testing. For these cases, you can enable it by adding the
following line of code:
Platform.isMemoryLeakCheckerActive = true
Note that enabling the checker for the application runtime is not recommended.
166
Kotlin/JS
Kotlin/JS is receiving evolutionary changes in 1.5.0. We're continuing our work on moving the JS IR compiler backend towards stable and
shipping other updates:
Upgrade
to
webpack
5
The Kotlin/JS Gradle plugin now uses webpack 5 for browser targets instead of webpack 4. This is a major webpack upgrade that brings
incompatible changes. If you're using a custom webpack configuration, be sure to check the webpack 5 release notes.
Frameworks
and
libraries
for
the
IR
compiler
The Kotlin/JS IR compiler is in Alpha. It may change incompatibly and require manual migration in the future. We would
appreciate your feedback on it in YouTrack.
Along with working on the IR-based backend for Kotlin/JS compiler, we encourage and help library authors to build their projects in both
mode. This means they are able to produce artifacts for both Kotlin/JS compilers, therefore growing the ecosystem for the new compiler.
Many well-known frameworks and libraries are already available for the IR backend: KVision, fritz2, doodle, and others. If you're using
them in your project, you can already build it with the IR backend and see the benefits it brings.
If you're writing your own library, compile it in the 'both' mode so that your clients can also use it with the new compiler.
Kotlin
Multiplatform
In Kotlin 1.5.0, choosing a testing dependency for each platform has been simplified and it is now done automatically by the Gradle
plugin.
A new API for getting a char category is now available in multiplatform projects.
Standard
library
The standard library has received a range of changes and improvements, from stabilizing experimental parts to adding new features:
167
New API for getting a char category now available in multiplatform code
You can learn more about the standard library changes in this blog post.
Gif
Stable
unsigned
integer
types
The UInt, ULong, UByte, UShort unsigned integer types are now Stable. The same goes for operations on these types, ranges, and
progressions of them. Unsigned arrays and operations on them remain in Beta.
Stable
locale-agnostic
API
for
upper/lowercasing
text
This release brings a new locale-agnostic API for uppercase/lowercase text conversion. It provides an alternative to the toLowerCase(),
toUpperCase(), capitalize(), and decapitalize() API functions, which are locale-sensitive. The new API helps you avoid errors due to different
locale settings.
String.toUpperCase() String.uppercase()
String.toLowerCase() String.lowercase()
168
Earlier versions 1.5.0 alternative
For Kotlin/JVM, there are also overloaded uppercase(), lowercase(), and titlecase() functions with an explicit Locale parameter.
The old API functions are marked as deprecated and will be removed in a future release.
See the full list of changes to the text processing functions in KEEP.
Stable
char-to-integer
conversion
API
Starting from Kotlin 1.5.0, new char-to-code and char-to-digit conversion functions are Stable. These functions replace the current API
functions, which were often confused with the similar string-to-Int conversion.
The new API removes this naming confusion, making the code behavior more transparent and unambiguous.
This release introduces Char conversions that are divided into the following sets of clearly named functions:
Functions to get the integer code of Char and to construct Char from the given code:
169
fun Char.digitToIntOrNull(radix: Int): Int?
An extension function for Int to convert the non-negative single digit it represents to the corresponding Char representation:
The old conversion APIs, including Number.toChar() with its implementations (all except Int.toChar()) and Char extensions for conversion
to a numeric type, like Char.toInt(), are now deprecated.
Stable
Path
API
The experimental Path API with extensions for java.nio.file.Path is now Stable.
Floored
division
and
the
mod
operator
New operations for modular arithmetics have been added to the standard library:
floorDiv() returns the result of floored division. It is available for integer types.
mod() returns the remainder of floored division (modulus). It is available for all numeric types.
These operations look quite similar to the existing division of integers and rem() function (or the %operator), but they work differently on
negative numbers:
a.floorDiv(b) differs from a regular / in that floorDiv rounds the result down (towards the lesser integer), whereas / truncates the result to
the integer closer to 0.
a.mod(b) is the difference between a and a.floorDiv(b) * b. It's either zero or has the same sign as b, while a % b can have a different
one.
fun main() {
//sampleStart
println("Floored division -5/3: ${(-5).floorDiv(3)}")
println( "Modulus: ${(-5).mod(3)}")
println("Truncated division -5/3: ${-5 / 3}")
println( "Remainder: ${-5 % 3}")
//sampleEnd
}
Duration
API
changes
170
The Duration API is Experimental. It may be dropped or changed at any time. Use it only for evaluation purposes. We would
appreciate hearing your feedback on it in YouTrack.
There is an experimental Duration class for representing duration amounts in different time units. In 1.5.0, the Duration API has received
the following changes:
Internal value representation now uses Long instead of Double to provide better precision.
There is a new API for conversion to a particular time unit in Long. It comes to replace the old API, which operates with Double values
and is now deprecated. For example, Duration.inWholeMinutes returns the value of the duration expressed as Long and replaces
Duration.inMinutes.
There are new companion functions for constructing a Duration from a number. For example, Duration.seconds(Int) creates a Duration
object representing an integer number of seconds. Old extension properties like Int.seconds are now deprecated.
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
@ExperimentalTime
fun main() {
//sampleStart
val duration = Duration.milliseconds(120000)
println("There are ${duration.inWholeSeconds} seconds in ${duration.inWholeMinutes} minutes")
//sampleEnd
}
New
API
for
getting
a
char
category
now
available
in
multiplatform
code
Kotlin 1.5.0 introduces the new API for getting a character's category according to Unicode in multiplatform projects. Several functions are
now available in all the platforms and in the common code.
Char.isDigit()
Char.isLetter()
Char.isLetterOrDigit()
fun main() {
//sampleStart
val chars = listOf('a', '1', '+')
val (letterOrDigitList, notLetterOrDigitList) = chars.partition { it.isLetterOrDigit() }
println(letterOrDigitList) // [a, 1]
println(notLetterOrDigitList) // [+]
//sampleEnd
}
Char.isLowerCase()
Char.isUpperCase()
Char.isTitleCase()
fun main() {
171
//sampleStart
val chars = listOf('Dž', 'Lj', 'Nj', 'Dz', '1', 'A', 'a', '+')
val (titleCases, notTitleCases) = chars.partition { it.isTitleCase() }
println(titleCases) // [Dž, Lj, Nj, Dz]
println(notTitleCases) // [1, A, a, +]
//sampleEnd
}
Char.isDefined()
Char.isISOControl()
The property Char.category and its return type enum class CharCategory, which indicates a char's general category according to Unicode,
are now also available in multiplatform projects.
New
collections
function
firstNotNullOf()
The new firstNotNullOf() and firstNotNullOfOrNull() functions combine mapNotNull() with first() or firstOrNull(). They map the original
collection with the custom selector function and return the first non-null value. If there is no such value, firstNotNullOf() throws an
exception, and firstNotNullOfOrNull() returns null.
fun main() {
//sampleStart
val data = listOf("Kotlin", "1.5")
println(data.firstNotNullOf(String::toDoubleOrNull))
println(data.firstNotNullOfOrNull(String::toIntOrNull))
//sampleEnd
}
Strict
version
of
String?.toBoolean()
Two new functions introduce case-sensitive strict versions of the existing String?.toBoolean():
String.toBooleanStrict() throws an exception for all inputs except the literals true and false.
String.toBooleanStrictOrNull() returns null for all inputs except the literals true and false.
fun main() {
//sampleStart
println("true".toBooleanStrict())
println("1".toBooleanStrictOrNull())
// println("1".toBooleanStrict()) // Exception
//sampleEnd
}
kotlin-test
library
The kotlin-test library introduces some new features:
172
Assertion function updates
Simplified
test
dependencies
usage
in
multiplatform
projects
Now you can use the kotlin-test dependency to add dependencies for testing in the commonTest source set, and the Gradle plugin will
infer the corresponding platform dependencies for each test source set:
kotlin-test-junit for JVM source sets, see automatic choice of a testing framework for Kotlin/JVM source sets
Additionally, you can use the kotlin-test dependency in any shared or platform-specific source set.
An existing kotlin-test setup with explicit dependencies will continue to work both in Gradle and in Maven.
Automatic
selection
of
a
testing
framework
for
Kotlin/JVM
source
sets
The Gradle plugin now chooses and adds a dependency on a testing framework automatically. All you need to do is add the dependency
kotlin-test in the common source set.
Gradle uses JUnit 4 by default. Therefore, the kotlin("test") dependency resolves to the variant for JUnit 4, namely kotlin-test-junit:
Kotlin
kotlin {
sourceSets {
val commonTest by getting {
dependencies {
implementation(kotlin("test")) // This brings the dependency
// on JUnit 4 transitively
}
}
}
}
Groovy
kotlin {
sourceSets {
commonTest {
dependencies {
implementation kotlin("test") // This brings the dependency
// on JUnit 4 transitively
}
}
}
}
You can choose JUnit 5 or TestNG by calling useJUnitPlatform() or useTestNG() in the test task:
tasks {
173
test {
// enable TestNG support
useTestNG()
// or
// enable JUnit Platform (a.k.a. JUnit 5) support
useJUnitPlatform()
}
}
You can disable automatic testing framework selection by adding the line kotlin.test.infer.jvm.variant=false to the project's
gradle.properties.
Assertion
function
updates
This release brings new assertion functions and improves the existing ones.
You can use the new assertIs<T> and assertIsNot<T> to check the type of a value:
@Test
fun testFunction() {
val s: Any = "test"
assertIs<String>(s) // throws AssertionError mentioning the actual type of s if the assertion fails
// can now print s.length because of contract in assertIs
println("${s.length}")
}
Because of type erasure, this assert function only checks whether the value is of the List type in the following example and doesn't
check whether it's a list of the particular String element type: assertIs<List<String>>(value).
Comparing the container content for arrays, sequences, and arbitrary iterables
There is a new set of overloaded assertContentEquals() functions for comparing content for different collections that don't implement
structural equality:
@Test
fun test() {
val expectedArray = arrayOf(1, 2, 3)
val actualArray = Array(3) { it + 1 }
assertContentEquals(expectedArray, actualArray)
}
New overloads to assertEquals() and assertNotEquals() for Double and Float numbers
There are new overloads for the assertEquals() function that make it possible to compare two Double or Float numbers with absolute
precision. The precision value is specified as the third parameter of the function:
@Test
fun test() {
val x = sin(PI)
// precision parameter
val tolerance = 0.000001
assertEquals(0.0, x, tolerance)
174
}
You can now check whether the collection or element contains something with the assertContains() function. You can use it with Kotlin
collections and elements that have the contains() operator, such as IntRange, String, and others:
@Test
fun test() {
val sampleList = listOf<String>("sample", "sample2")
val sampleString = "sample"
assertContains(sampleList, sampleString) // element in collection
assertContains(sampleString, "amp") // substring in string
}
From now on, you can use these as inline functions, so it's possible to call suspend functions inside a lambda expression:
@Test
fun test() = runBlocking<Unit> {
val deferred = async { "Kotlin is nice" }
assertTrue("Kotlin substring should be present") {
deferred.await() .contains("Kotlin")
}
}
kotlinx
libraries
Along with Kotlin 1.5.0, we are releasing new versions of the kotlinx libraries:
kotlinx.coroutines 1.5.0-RC
kotlinx.serialization 1.2.1
kotlinx-datetime 0.2.0
Coroutines
1.5.0-RC
kotlinx.coroutines 1.5.0-RC is here with:
And more
Starting with Kotlin 1.5.0, experimental coroutines are disabled and the -Xcoroutines=experimental flag is no longer supported.
Learn more in the changelog and the kotlinx.coroutines 1.5.0 release blog post.
175
Gif
Serialization
1.2.1
kotlinx.serialization 1.2.1 is here with:
And more
Learn more in the changelog and the kotlinx.serialization 1.2.1 release blog post.
Gif
176
dateTime
0.2.0
kotlinx-datetime 0.2.0 is here with:
And more
Learn more in the changelog and the kotlinx-datetime 0.2.0 release blog post.
Migrating
to
Kotlin
1.5.0
IntelliJ IDEA and Android Studio will suggest updating the Kotlin plugin to 1.5.0 once it is available.
To migrate existing projects to Kotlin 1.5.0, just change the Kotlin version to 1.5.0 and re-import your Gradle or Maven project. Learn how
to update to Kotlin 1.5.0.
To start a new project with Kotlin 1.5.0, update the Kotlin plugin and run the Project Wizard from File | New | Project.
The new command-line compiler is available for downloading on the GitHub release page.
Kotlin 1.5.0 is a feature release and therefore can bring incompatible changes to the language. Find the detailed list of such changes in the
Compatibility Guide for Kotlin 1.5.
What's
new
in
Kotlin
1.4.30
Release date: 3 February 2021
Kotlin 1.4.30 offers preview versions of new language features, promotes the new IR backend of the Kotlin/JVM compiler to Beta, and
ships various performance and functional improvements.
You can also learn about new features in this blog post.
Language
features
Kotlin 1.5.0 is going to deliver new language features – JVM records support, sealed interfaces, and Stable inline classes. In Kotlin 1.4.30,
you can try these features and improvements in preview mode. We would be very grateful if you share your feedback with us in the
corresponding YouTrack tickets, as that will allow us to address it before the release of 1.5.0.
To enable these language features and improvements in preview mode, you need to opt in by adding specific compiler options. See the
sections below for details.
Learn more about the new features preview in this blog post.
JVM
records
support
177
The JVM records feature is Experimental. It may be dropped or changed at any time. Opt-in is required (see the details below),
and you should use it only for evaluation purposes. We would appreciate your feedback on it in YouTrack.
The JDK 16 release includes plans to stabilize a new Java class type called record. To provide all the benefits of Kotlin and maintain its
interoperability with Java, Kotlin is introducing experimental record class support.
You can use record classes that are declared in Java just like classes with properties in Kotlin. No additional steps are required.
Starting with 1.4.30, you can declare the record class in Kotlin using the @JvmRecord annotation for a data class:
@JvmRecord
data class User(val name: String, val age: Int)
To try the preview version of JVM records, add the compiler options -Xjvm-enable-preview and -language-version 1.5.
We're continuing to work on JVM records support, and we would be very grateful if you would share your feedback with us using this
YouTrack ticket.
Sealed
interfaces
Sealed interfaces are Experimental. They may be dropped or changed at any time. Opt-in is required (see the details below), and
you should use them only for evaluation purposes. We would appreciate your feedback on them in YouTrack.
In Kotlin 1.4.30, we're shipping the prototype of sealed interfaces. They complement sealed classes and make it possible to build more
flexible restricted class hierarchies.
They can serve as "internal" interfaces that cannot be implemented outside the same module. You can rely on that fact, for example, to
write exhaustive when expressions.
Another use-case: with sealed interfaces, you can inherit a class from two or more sealed superclasses.
178
class Rectangle(override val vertices: List<Point>): Fillable, Polygon {
override fun fill() { /*...*/ }
}
To try the preview version of sealed interfaces, add the compiler option -language-version 1.5. Once you switch to this version, you'll be
able to use the sealed modifier on interfaces. We would be very grateful if you would share your feedback with us using this YouTrack
ticket.
Package-wide
sealed
class
hierarchies
Package-wide hierarchies of sealed classes are Experimental. They may be dropped or changed at any time. Opt-in is required
(see the details below), and you should use them only for evaluation purposes. We would appreciate your feedback on them in
YouTrack.
Sealed classes can now form more flexible hierarchies. They can have subclasses in all files of the same compilation unit and the same
package. Previously, all subclasses had to appear in the same file.
Direct subclasses may be top-level or nested inside any number of other named classes, named interfaces, or named objects. The
subclasses of a sealed class must have a name that is properly qualified – they cannot be local nor anonymous objects.
To try package-wide hierarchies of sealed classes, add the compiler option -language-version 1.5. We would be very grateful if you would
share your feedback with us using this YouTrack ticket.
Improved
inline
classes
Inline value classes 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. We would appreciate your feedback on the inline classes feature in YouTrack.
Kotlin 1.4.30 promotes inline classes to Beta and brings the following features and improvements to them:
Since inline classes are value-based, you can define them using the value modifier. The inline and value modifiers are now equivalent to
each other. In future Kotlin versions, we're planning to deprecate the inline modifier.
From now on, Kotlin requires the @JvmInline annotation before a class declaration for the JVM backend:
Inline classes can have init blocks. You can add code to be executed right after the class is instantiated:
@JvmInline
179
value class Negative(val x: Int) {
init {
require(x < 0) { }
}
}
Calling functions with inline classes from Java code: before Kotlin 1.4.30, you couldn't call functions that accept inline classes from
Java because of mangling. From now on, you can disable mangling manually. To call such functions from Java code, you should add
the @JvmName annotation before the function declaration:
@JvmName("computeUInt")
fun compute(x: UInt) { }
In this release, we've changed the mangling scheme for functions to fix the incorrect behavior. These changes led to ABI changes.
Starting with 1.4.30, the Kotlin compiler uses a new mangling scheme by default. Use the -Xuse-14-inline-classes-mangling-scheme
compiler flag to force the compiler to use the old 1.4.0 mangling scheme and preserve binary compatibility.
Kotlin 1.4.30 promotes inline classes to Beta and we are planning to make them Stable in future releases. We'd be very grateful if you
would share your feedback with us using this YouTrack ticket.
To try the preview version of inline classes, add the compiler option -Xinline-classes or -language-version 1.5.
Kotlin/JVM
JVM
IR
compiler
backend
reaches
Beta
The IR-based compiler backend for Kotlin/JVM, which was presented in 1.4.0 in Alpha, has reached Beta. This is the last pre-stable level
before the IR backend becomes the default for the Kotlin/JVM compiler.
We're now dropping the restriction on consuming binaries produced by the IR compiler. Previously, you could use code compiled by the
new JVM IR backend only if you had enabled the new backend. Starting from 1.4.30, there is no such limitation, so you can use the new
backend to build components for third-party use, such as libraries. Try the Beta version of the new backend and share your feedback in
our issue tracker.
To enable the new JVM IR backend, add the following lines to the project's configuration file:
In Gradle:
Kotlin
tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile::class) {
kotlinOptions.useIR = true
}
Groovy
180
tasks.withType(org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile) {
kotlinOptions.useIR = true
}
In Maven:
<configuration>
<args>
<arg>-Xuse-ir</arg>
</args>
</configuration>
Learn more about the changes that the JVM IR backend brings in this blog post.
Kotlin/Native
Performance
improvements
Kotlin/Native has received a variety of performance improvements in 1.4.30, which has resulted in faster compilation times. For example,
the time required to rebuild the framework in the Networking and data storage with Kotlin Multiplatform Mobile sample has decreased from
9.5 seconds (in 1.4.10) to 4.5 seconds (in 1.4.30).
Apple
watchOS
64-bit
simulator
target
The x86 simulator target has been deprecated for watchOS since version 7.0. To keep up with the latest watchOS versions, Kotlin/Native
has the new target watchosX64 for running the simulator on 64-bit architecture.
Support
for
Xcode
12.2
libraries
We have added support for the new libraries delivered with Xcode 12.2. You can now use them from Kotlin code.
Kotlin/JS
Lazy
initialization
of
top-level
properties
Lazy initialization of top-level properties is Experimental. It may be dropped or changed at any time. Opt-in is required (see the
details below), and you should use it only for evaluation purposes. We would appreciate your feedback on it in YouTrack.
The IR backend for Kotlin/JS is receiving a prototype implementation of lazy initialization for top-level properties. This reduces the need to
initialize all top-level properties when the application starts, and it should significantly improve application start-up times.
We'll keep working on the lazy initialization, and we ask you to try the current prototype and share your thoughts and results in this
YouTrack ticket or the #javascript channel in the official Kotlin Slack (get an invite here).
To use the lazy initialization, add the -Xir-property-lazy-initialization compiler option when compiling the code with the JS IR compiler.
181
Gradle
project
improvements
Support
the
Gradle
configuration
cache
Starting with 1.4.30, the Kotlin Gradle plugin supports the configuration cache feature. It speeds up the build process: once you run the
command, Gradle executes the configuration phase and calculates the task graph. Gradle caches the result and reuses it for subsequent
builds.
To start using this feature, you can use the Gradle command or set up the IntelliJ based IDE.
Standard
library
Locale-agnostic
API
for
upper/lowercasing
text
The locale-agnostic API feature is Experimental. It may be dropped or changed at any time. Use it only for evaluation purposes.
We would appreciate your feedback on it in YouTrack.
This release introduces the experimental locale-agnostic API for changing the case of strings and characters. The current toLowerCase(),
toUpperCase(), capitalize(), decapitalize() API functions are locale-sensitive. This means that different platform locale settings can affect
code behavior. For example, in the Turkish locale, when the string "kotlin" is converted using toUpperCase, the result is "KOTLİN", not
"KOTLIN".
// current API
println("Needs to be capitalized".toUpperCase()) // NEEDS TO BE CAPITALIZED
// new API
println("Needs to be capitalized".uppercase()) // NEEDS TO BE CAPITALIZED
String.toUpperCase() String.uppercase()
String.toLowerCase() String.lowercase()
182
Earlier versions 1.4.30 alternative
For Kotlin/JVM, there are also overloaded uppercase(), lowercase(), and titlecase() functions with an explicit Locale parameter.
See the full list of changes to the text processing functions in KEEP.
Clear
Char-to-code
and
Char-to-digit
conversions
The unambiguous API for the Char conversion feature is Experimental. It may be dropped or changed at any time. Use it only for
evaluation purposes. We would appreciate your feedback on it in YouTrack.
The current Char to numbers conversion functions, which return UTF-16 codes expressed in different numeric types, are often confused
with the similar String-to-Int conversion, which returns the numeric value of a string:
"4".toInt() // returns 4
'4'.toInt() // returns 52
// and there was no common function that would return the numeric value 4 for Char '4'
To avoid this confusion we've decided to separate Char conversions into two following sets of clearly named functions:
Functions to get the integer code of Char and to construct Char from the given code:
An extension function for Int to convert the non-negative single digit it represents to the corresponding Char representation:
183
See more details in KEEP.
Serialization
updates
Along with Kotlin 1.4.30, we are releasing kotlinx.serialization 1.1.0-RC, which includes some new features:
Inline
classes
serialization
support
Starting with Kotlin 1.4.30, you can make inline classes serializable:
@Serializable
inline class Color(val rgb: Int)
The serialization framework does not box serializable inline classes when they are used in other serializable classes.
Unsigned
primitive
type
serialization
support
Starting from 1.4.30, you can use standard JSON serializers of kotlinx.serialization for unsigned primitive types: UInt, ULong, UByte, and
UShort:
@Serializable
class Counter(val counted: UByte, val description: String)
fun main() {
val counted = 239.toUByte()
println(Json.encodeToString(Counter(counted, "tries")))
}
What's
new
in
Kotlin
1.4.20
Release date: 23 November 2020
Kotlin 1.4.20 offers a number of new experimental features and provides fixes and improvements for existing features, including those
added in 1.4.0.
You can also learn about new features with more examples in this blog post.
Kotlin/JVM
184
Improvements of Kotlin/JVM are intended to keep it up with the features of modern Java versions:
Java 15 target
Java
15
target
Now Java 15 is available as a Kotlin/JVM target.
invokedynamic
string
concatenation
invokedynamic string concatenation is Experimental. It may be dropped or changed at any time. Opt-in is required (see details
below). Use it only for evaluation purposes. We appreciate your feedback on it in YouTrack.
Kotlin 1.4.20 can compile string concatenations into dynamic invocations on JVM 9+ targets, therefore improving the performance.
String.plus in the operator (a + b), explicit (a.plus(b)), and reference ((a::plus)(b)) form.
string templates except for ones with a single non-constant argument (see KT-42457).
To enable invokedynamic string concatenation, add the -Xstring-concat compiler option with one of the following values:
Kotlin/JS
Kotlin/JS keeps evolving fast, and in 1.4.20 you can find a number experimental features and improvements:
Gradle
DSL
changes
The Gradle DSL for Kotlin/JS receives a number of updates which simplify project setup and customization. This includes webpack
configuration adjustments, modifications to the auto-generated package.json file, and improved control over transitive dependencies.
185
To enable CSS support by default for all three tasks, add the following snippet in the build.gradle(.kts) of your project:
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
binaries.executable()
}
To add custom fields to your package.json, use the customField function in the compilation's packageJson block:
kotlin {
js(BOTH) {
compilations["main"].packageJson {
customField("hello", mapOf("one" to 1, "two" to 2))
}
}
}
Support for selective yarn dependency resolutions is Experimental. It may be dropped or changed at any time. Use it only for
evaluation purposes. We appreciate your feedback on it in YouTrack.
Kotlin 1.4.20 provides a way of configuring Yarn's selective dependency resolutions - the mechanism for overriding dependencies of the
packages you depend on.
You can use it through the YarnRootExtension inside the YarnPlugin in Gradle. To affect the resolved version of a package for your project,
use the resolution function passing in the package name selector (as specified by Yarn) and the version to which it should resolve.
rootProject.plugins.withType<YarnPlugin> {
rootProject.the<YarnRootExtension>().apply {
resolution("react", "16.0.0")
resolution("processor/decamelize", "3.0.0")
}
}
Here, all of your npm dependencies which require react will receive version 16.0.0, and processor will receive its dependency decamelize
as version 3.0.0.
186
Disabling granular workspaces is Experimental. It may be dropped or changed at any time. Use it only for evaluation purposes.
We appreciate your feedback on it in YouTrack.
To speed up build times, the Kotlin/JS Gradle plugin only installs the dependencies which are required for a particular Gradle task. For
example, the webpack-dev-server package is only installed when you execute one of the *Run tasks, and not when you execute the
assemble task. Such behavior can potentially bring problems when you run multiple Gradle processes in parallel. When the dependency
requirements clash, the two installations of npm packages can cause errors.
To resolve this issue, Kotlin 1.4.20 includes an option to disable these so-called granular workspaces. This feature is currently available
through the YarnRootExtension inside the YarnPlugin in Gradle. To use it, add the following snippet to your build.gradle.kts file:
rootProject.plugins.withType<YarnPlugin> {
rootProject.the<YarnRootExtension>().disableGranularWorkspaces()
}
New
Wizard
templates
To give you more convenient ways to customize your project during creation, the project wizard for Kotlin comes with new templates for
Kotlin/JS applications:
Browser Application - a minimal Kotlin/JS Gradle project that runs in the browser.
React Application - a React app that uses the appropriate kotlin-wrappers. It provides options to enable integrations for style-sheets,
navigational components, or state containers.
Node.js Application - a minimal project for running in a Node.js runtime. It comes with the option to directly include the experimental
kotlinx-nodejs package.
Ignoring
compilation
errors
with
IR
compiler
Ignore compilation errors mode is Experimental. It may be dropped or changed at any time. Opt-in is required (see details
below). Use it only for evaluation purposes. We appreciate your feedback on it in YouTrack.
The IR compiler for Kotlin/JS comes with a new experimental mode - compilation with errors. In this mode, you can run you code even if it
contains errors, for example, if you want to try certain things it when the whole application is not ready yet.
SEMANTIC: the compiler will accept code which is syntactically correct, but doesn't make sense semantically, such as val x: String = 3.
SYNTAX: the compiler will accept any code, even if it contains syntax errors.
To allow compilation with errors, add the -Xerror-tolerance-policy= compiler option with one of the values listed above.
Kotlin/Native
187
Kotlin/Native's priorities in 1.4.20 are performance and polishing existing features. These are the notable improvements:
Escape analysis
Escape
analysis
The escape analysis mechanism is Experimental. It may be dropped or changed at any time. Use it only for evaluation purposes.
We appreciate your feedback on it in YouTrack.
Kotlin/Native receives a prototype of the new escape analysis mechanism. It improves the runtime performance by allocating certain
objects on the stack instead of the heap. This mechanism shows a 10% average performance increase on our benchmarks, and we
continue improving it so that it speeds up the program even more.
The escape analysis runs in a separate compilation phase for the release builds (with the -opt compiler option).
If you want to disable the escape analysis phase, use the -Xdisable-phases=EscapeAnalysis compiler option.
Performance
improvements
and
bug
fixes
Kotlin/Native receives performance improvements and bug fixes in various components, including the ones added in 1.4.0, for example,
the code sharing mechanism.
Opt-in
wrapping
of
Objective-C
exceptions
The Objective-C exception wrapping mechanism is Experimental. It may be dropped or changed at any time. Opt-in is required
(see details below). Use it only for evaluation purposes. We appreciate your feedback on it in YouTrack.
Kotlin/Native now can handle exceptions thrown from Objective-C code in runtime to avoid program crashes.
You can opt in to wrap NSException's into Kotlin exceptions of type ForeignException. They hold the references to the original
NSException's. This lets you get the information about the root cause and handle it properly.
To enable wrapping of Objective-C exceptions, specify the -Xforeign-exception-mode objc-wrap option in the cinterop call or add
foreignExceptionMode = objc-wrap property to .def file. If you use CocoaPods integration, specify the option in the pod {} build script
block of a dependency like this:
pod("foo") {
extraOpts = listOf("-Xforeign-exception-mode", "objc-wrap")
}
The default behavior remains unchanged: the program terminates when an exception is thrown from the Objective-C code.
188
CocoaPods
plugin
improvements
Kotlin 1.4.20 continues the set of improvements in CocoaPods integration. Namely, you can try the following new features:
Extended DSL
Extended DSL
The DSL of adding CocoaPods dependencies to your Kotlin project receives new capabilites.
In addition to local Pods and Pods from the CocoaPods repository, you can add dependencies on the following types of libraries:
A static library.
Learn more about adding CocoaPods dependencies in Kotlin projects. Find examples in the Kotlin with CocoaPods sample.
If your Kotlin Pod has any Git, HTTP, or specRepo Pod dependency, you should also specify it in the Podfile.
When you add a library from the custom spec, you also should specify the location of specs at the beginning of your Podfile.
Now integration errors have a detailed description in IDEA. So if you have problems with your Podfile, you will immediately know how to fix
them.
Support
for
Xcode
12
libraries
We have added support for new libraries delivered with Xcode 12. Now you can use them from the Kotlin code.
Kotlin
Multiplatform
Updated
structure
of
multiplatform
library
publications
Starting from Kotlin 1.4.20, there is no longer a separate metadata publication. Metadata artifacts are now included in the root publication
which stands for the whole library and is automatically resolved to the appropriate platform-specific artifacts when added as a
dependency to the common source set.
189
Learn more about publishing a multiplatform library.
Projects and libraries without the hierarchical project structure remain compatible.
Standard
library
The standard library of Kotlin 1.4.20 offers new extensions for working with files and a better performance.
Extensions
for
java.nio.file.Path
Extensions for java.nio.file.Path are Experimental. They may be dropped or changed at any time. Opt-in is required (see details
below). Use them only for evaluation purposes. We appreciate your feedback on them in YouTrack.
Now the standard library provides experimental extensions for java.nio.file.Path. Working with the modern JVM file API in an idiomatic
Kotlin way is now similar to working with java.io.File extensions from the kotlin.io package.
The extensions are available in the kotlin.io.path package in the kotlin-stdlib-jdk7 module. To use the extensions, opt-in to the
experimental annotation @ExperimentalPathApi.
Improved
String.replace
function
performance
The new implementation of String.replace() speeds up the function execution. The case-sensitive variant uses a manual replacement loop
based on indexOf, while the case-insensitive one uses regular expression matching.
Kotlin
Android
Extensions
In 1.4.20 the Kotlin Android Extensions plugin becomes deprecated and Parcelable implementation generator moves to a separate plugin.
190
Deprecation
of
synthetic
views
Synthetic views were presented in the Kotlin Android Extensions plugin a while ago to simplify the interaction with UI elements and reduce
boilerplate. Now Google offers a native mechanism that does the same - Android Jetpack's view bindings, and we're deprecating
synthetic views in favor of those.
We extract the Parcelable implementations generator from kotlin-android-extensions and start the deprecation cycle for the rest of it -
synthetic views. For now, they will keep working with a deprecation warning. In the future, you'll need to switch your project to another
solution. Here are the guidelines that will help you migrate your Android project from synthetics to view bindings.
New
plugin
for
Parcelable
implementation
generator
The Parcelable implementation generator is now available in the new kotlin-parcelize plugin. Apply this plugin instead of kotlin-android-
extensions.
What's
new
in
Kotlin
1.4
Release date: 17 August 2020
In Kotlin 1.4.0, we ship a number of improvements in all of its components, with the focus on quality and performance. Below you will find
the list of the most important changes in Kotlin 1.4.0.
Language
features
and
improvements
Kotlin 1.4.0 comes with a variety of different language features and improvements. They include:
Trailing comma
SAM
conversions
for
Kotlin
interfaces
Before Kotlin 1.4.0, you could apply SAM (Single Abstract Method) conversions only when working with Java methods and Java interfaces
from Kotlin. From now on, you can use SAM conversions for Kotlin interfaces as well. To do so, mark a Kotlin interface explicitly as
functional with the fun modifier.
SAM conversion applies if you pass a lambda as an argument when an interface with only one single abstract method is expected as a
parameter. In this case, the compiler automatically converts the lambda to an instance of the class that implements the abstract member
191
function.
fun main() {
println("Is 7 even? - ${isEven.accept(7)}")
}
Explicit
API
mode
for
library
authors
Kotlin compiler offers explicit API mode for library authors. In this mode, the compiler performs additional checks that help make the
library's API clearer and more consistent. It adds the following requirements for declarations exposed to the library's public API:
Visibility modifiers are required for declarations if the default visibility exposes them to the public API. This helps ensure that no
declarations are exposed to the public API unintentionally.
Explicit type specifications are required for properties and functions that are exposed to the public API. This guarantees that API users
are aware of the types of API members they use.
Depending on your configuration, these explicit APIs can produce errors (strict mode) or warnings (warning mode). Certain kinds of
declarations are excluded from such checks for the sake of readability and common sense:
primary constructors
override methods
To compile your module in the explicit API mode, add the following lines to your Gradle build script:
Kotlin
kotlin {
// for strict mode
explicitApi()
// or
explicitApi = ExplicitApiMode.Strict
// for warning mode
explicitApiWarning()
// or
explicitApi = ExplicitApiMode.Warning
}
Groovy
kotlin {
// for strict mode
explicitApi()
192
// or
explicitApi = 'strict'
// for warning mode
explicitApiWarning()
// or
explicitApi = 'warning'
}
When using the command-line compiler, switch to explicit API mode by adding the -Xexplicit-api compiler option with the value strict or
warning.
-Xexplicit-api={strict|warning}
Find more details about the explicit API mode in the KEEP.
Mixing
named
and
positional
arguments
In Kotlin 1.3, when you called a function with named arguments, you had to place all the arguments without names (positional arguments)
before the first named argument. For example, you could call f(1, y = 2), but you couldn't call f(x = 1, 2).
It was really annoying when all the arguments were in their correct positions but you wanted to specify a name for one argument in the
middle. It was especially helpful for making absolutely clear which attribute a boolean or null value belongs to.
In Kotlin 1.4, there is no such limitation – you can now specify a name for an argument in the middle of a set of positional arguments.
Moreover, you can mix positional and named arguments any way you like, as long as they remain in the correct order.
fun reformat(
str: String,
uppercaseFirstLetter: Boolean = true,
wordSeparator: Char = ' '
) {
// ...
}
Trailing
comma
With Kotlin 1.4 you can now add a trailing comma in enumerations such as argument and parameter lists, when entries, and components
of destructuring declarations. With a trailing comma, you can add new items and change their order without adding or removing commas.
This is especially helpful if you use multi-line syntax for parameters or values. After adding a trailing comma, you can then easily swap lines
with parameters or values.
fun reformat(
str: String,
uppercaseFirstLetter: Boolean = true,
wordSeparator: Character = ' ', //trailing comma
) {
// ...
}
193
"green",
"blue", //trailing comma
)
Callable
reference
improvements
Kotlin 1.4 supports more cases for using callable references:
fun main() {
println(apply(::foo))
}
Previously, you had to write additional overloads for the function apply to use the default argument values.
fun main() {
foo { returnsInt() } // this was the only way to do it before 1.4
foo(::returnsInt) // starting from 1.4, this also works
}
194
fun test() {
use0(::foo)
use1(::foo)
use2(::foo)
}
fun call() {}
fun takeSuspend(f: suspend () -> Unit) {}
fun test() {
takeSuspend { call() } // OK before 1.4
takeSuspend(::call) // In Kotlin 1.4, it also works
}
Using
break
and
continue
inside
when
expressions
included
in
loops
In Kotlin 1.3, you could not use unqualified break and continue inside when expressions included in loops. The reason was that these
keywords were reserved for possible fall-through behavior in when expressions.
That's why if you wanted to use break and continue inside when expressions in loops, you had to label them, which became rather
cumbersome.
In Kotlin 1.4, you can use break and continue without labels inside when expressions included in loops. They behave as expected by
terminating the nearest enclosing loop or proceeding to its next step.
New
tools
in
the
IDE
With Kotlin 1.4, you can use the new tools in IntelliJ IDEA to simplify Kotlin development:
195
Coroutine Debugger
New
flexible
Project
Wizard
With the flexible new Kotlin Project Wizard, you have a place to easily create and configure different types of Kotlin projects, including
multiplatform projects, which can be difficult to configure without a UI.
1. Select the project template, depending on what you're trying to do. More templates will be added in the future.
2. Select the build system – Gradle (Kotlin or Groovy DSL), Maven, or IntelliJ IDEA.
The Kotlin Project Wizard will only show the build systems supported on the selected project template.
Then you can finish creating your project or, optionally, configure the project on the next screen:
5. Configure module and target settings, for example, the target JVM version, target template, and test framework.
196
Kotlin Project Wizard - Configure targets
In the future, we are going to make the Kotlin Project Wizard even more flexible by adding more configuration options and templates.
You can try out the new Kotlin Project Wizard by working through these tutorials:
Coroutine
Debugger
Many people already use coroutines for asynchronous programming. But when it came to debugging, working with coroutines before
Kotlin 1.4, could be a real pain. Since coroutines jumped between threads, it was difficult to understand what a specific coroutine was
doing and check its context. In some cases, tracking steps over breakpoints simply didn't work. As a result, you had to rely on logging or
mental effort to debug code that used coroutines.
In Kotlin 1.4, debugging coroutines is now much more convenient with the new functionality shipped with the Kotlin plugin.
The Debug Tool Window now contains a new Coroutines tab. In this tab, you can find information about both currently running and
suspended coroutines. The coroutines are grouped by the dispatcher they are running on.
197
Debugging coroutines
See the values of local and captured variables for both running and suspended coroutines.
See a full coroutine creation stack, as well as a call stack inside the coroutine. The stack includes all frames with variable values, even
those that would be lost during standard debugging.
If you need a full report containing the state of each coroutine and its stack, right-click inside the Coroutines tab, and then click Get
Coroutines Dump. Currently, the coroutines dump is rather simple, but we're going to make it more readable and helpful in future versions
of Kotlin.
Coroutines Dump
Learn more about debugging coroutines in this blog post and IntelliJ IDEA documentation.
New
compiler
The new Kotlin compiler is going to be really fast; it will unify all the supported platforms and provide an API for compiler extensions. It's a
long-term project, and we've already completed several steps in Kotlin 1.4.0:
New JVM and JS IR backends. They will become the default once we stabilize them.
New
more
powerful
type
inference
algorithm
Kotlin 1.4 uses a new, more powerful type inference algorithm. This new algorithm was already available to try in Kotlin 1.3 by specifying a
198
compiler option, and now it's used by default. You can find the full list of issues fixed in the new algorithm in YouTrack. Here you can find
some of the most noticeable improvements:
//sampleStart
val rulesMap: Map<String, (String?) -> Boolean> = mapOf(
"weak" to { it != null },
"medium" to { !it.isNullOrBlank() },
"strong" to { it != null && "^[a-zA-Z0-9]+$".toRegex().matches(it) }
)
//sampleEnd
fun main() {
println(rulesMap.getValue("weak")("abc!"))
println(rulesMap.getValue("strong")("abc"))
println(rulesMap.getValue("strong")("abc!"))
}
In Kotlin 1.3, you needed to introduce an explicit lambda parameter or replace to with a Pair constructor with explicit generic arguments to
make it work.
In Kotlin 1.4, thanks to the new inference algorithm, the last expression inside a lambda gets smart cast, and this new, more precise type
is used to infer the resulting lambda type. Thus, the type of the result variable becomes String.
In Kotlin 1.3, you often needed to add explicit casts (either !! or type casts like as String) to make such cases work, and now these casts
have become unnecessary.
199
In Kotlin 1.3, you couldn't access a member reference of a smart cast type. Now in Kotlin 1.4 you can:
import kotlin.reflect.KFunction
//sampleStart
fun perform(animal: Animal) {
val kFunction: KFunction<*> = when (animal) {
is Cat -> animal::meow
is Dog -> animal::woof
}
kFunction.call()
}
//sampleEnd
fun main() {
perform(Cat())
}
You can use different member references animal::meow and animal::woof after the animal variable has been smart cast to specific types
Cat and Dog. After type checks, you can access member references corresponding to subtypes.
import kotlin.properties.Delegates
fun main() {
var prop: String? by Delegates.observable(null) { p, old, new ->
println("$old → $new")
}
prop = "abc"
prop = "xyz"
}
The new algorithm fixes this issue, and you can pass a lambda instead of a SAM interface in any case, which is the way you'd naturally
expect it to work.
// FILE: A.java
public class A {
200
public static void foo(Runnable r1, Runnable r2) {}
}
// FILE: test.kt
fun test(r1: Runnable) {
A.foo(r1) {} // Works in Kotlin 1.4
}
import java.lang.Runnable
fun test() {
foo { } // OK
}
In Kotlin 1.3, you would have had to declare the function foo above in Java code to perform a SAM conversion.
Unified
backends
and
extensibility
In Kotlin, we have three backends that generate executables: Kotlin/JVM, Kotlin/JS, and Kotlin/Native. Kotlin/JVM and Kotlin/JS don't
share much code since they were developed independently of each other. Kotlin/Native is based on a new infrastructure built around an
intermediate representation (IR) for Kotlin code.
We are now migrating Kotlin/JVM and Kotlin/JS to the same IR. As a result, all three backends share a lot of logic and have a unified
pipeline. This allows us to implement most features, optimizations, and bug fixes only once for all platforms. Both new IR-based back-
ends are in Alpha.
A common backend infrastructure also opens the door for multiplatform compiler extensions. You will be able to plug into the pipeline and
add custom processing and transformations that will automatically work for all platforms.
We encourage you to use our new JVM IR and JS IR backends, which are currently in Alpha, and share your feedback with us.
Kotlin/JVM
Kotlin 1.4.0 includes a number of JVM-specific improvements, such as:
New
JVM
IR
backend
Along with Kotlin/JS, we are migrating Kotlin/JVM to the unified IR backend, which allows us to implement most features and bug fixes
once for all platforms. You will also be able to benefit from this by creating multiplatform extensions that will work for all platforms.
Kotlin 1.4.0 does not provide a public API for such extensions yet, but we are working closely with our partners, including Jetpack
201
Compose, who are already building their compiler plugins using our new backend.
We encourage you to try out the new Kotlin/JVM backend, which is currently in Alpha, and to file any issues and feature requests to our
issue tracker. This will help us to unify the compiler pipelines and bring compiler extensions like Jetpack Compose to the Kotlin community
more quickly.
To enable the new JVM IR backend, specify an additional compiler option in your Gradle build script:
kotlinOptions.useIR = true
If you enable Jetpack Compose, you will automatically be opted in to the new JVM backend without needing to specify the
compiler option in kotlinOptions.
When using the command-line compiler, add the compiler option -Xuse-ir.
You can use code compiled by the new JVM IR backend only if you've enabled the new backend. Otherwise, you will get an
error. Considering this, we don't recommend that library authors switch to the new backend in production.
New
modes
for
generating
default
methods
When compiling Kotlin code to targets JVM 1.8 and above, you could compile non-abstract methods of Kotlin interfaces into Java's
default methods. For this purpose, there was a mechanism that includes the @JvmDefault annotation for marking such methods and the -
Xjvm-default compiler option that enables processing of this annotation.
In 1.4.0, we've added a new mode for generating default methods: -Xjvm-default=all compiles all non-abstract methods of Kotlin
interfaces to default Java methods. For compatibility with the code that uses the interfaces compiled without default, we also added all-
compatibility mode.
For more information about default methods in the Java interop, see the interoperability documentation and this blog post.
Unified
exception
type
for
null
checks
Starting from Kotlin 1.4.0, all runtime null checks will throw a java.lang.NullPointerException instead of KotlinNullPointerException,
IllegalStateException, IllegalArgumentException, and 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 checkNotNull or requireNotNull.
This change increases the number of 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.
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.
Type
annotations
in
the
JVM
bytecode
Kotlin can now generate type annotations in the JVM bytecode (target version 1.8+), so that they become available in Java reflection at
runtime. To emit the type annotation in the bytecode, follow these steps:
1. Make sure that your declared annotation has a proper annotation target (Java's ElementType.TYPE_USE or Kotlin's
AnnotationTarget.TYPE) and retention (AnnotationRetention.RUNTIME).
202
2. Compile the annotation class declaration to JVM bytecode target version 1.8+. You can specify it with -jvm-target=1.8 compiler option.
3. Compile the code that uses the annotation to JVM bytecode target version 1.8+ (-jvm-target=1.8) and add the -Xemit-jvm-type-
annotations compiler option.
Note that the type annotations from the standard library aren't emitted in the bytecode for now because the standard library is compiled
with the target version 1.6.
Type annotations on method parameters, method return types and property types;
In the following example, the @Foo annotation on the String type can be emitted to the bytecode and then used by the library code:
@Target(AnnotationTarget.TYPE)
annotation class Foo
class A {
fun foo(): @Foo String = "OK"
}
Kotlin/JS
On the JS platform, Kotlin 1.4.0 provides the following improvements:
New JS IR backend
New
Gradle
DSL
The kotlin.js Gradle plugin comes with an adjusted Gradle DSL, which provides a number of new configuration options and is more closely
aligned to the DSL used by the kotlin-multiplatform plugin. Some of the most impactful changes include:
Explicit toggles for the creation of executable files via binaries.executable(). Read more about the executing Kotlin/JS and its
environment here.
Configuration of webpack's CSS and style loaders from within the Gradle configuration via cssSupport. Read more about using CSS
and style loaders here.
Improved management for npm dependencies, with mandatory version numbers or semver version ranges, as well as support for
development, peer, and optional npm dependencies using devNpm, optionalNpm and peerNpm. Read more about dependency
management for npm packages directly from Gradle here.
Stronger integrations for Dukat, the generator for Kotlin external declarations. External declarations can now be generated at build time,
or can be manually generated via a Gradle task. Read more about how to use the integration here.
New
JS
IR
backend
The IR backend for Kotlin/JS, which currently has Alpha stability, provides some new functionality specific to the Kotlin/JS target which is
focused around the generated code size through dead code elimination, and improved interoperation with JavaScript and TypeScript,
among others.
To enable the Kotlin/JS IR backend, set the key kotlin.js.compiler=ir in your gradle.properties, or pass the IR compiler type to the js
203
function of your Gradle build script:
kotlin {
js(IR) { // or: LEGACY, BOTH
// . . .
}
binaries.executable()
}
For more detailed information about how to configure the new backend, check out the Kotlin/JS IR compiler documentation.
With the new @JsExport annotation and the ability to generate TypeScript definitions from Kotlin code, the Kotlin/JS IR compiler backend
improves JavaScript & TypeScript interoperability. This also makes it easier to integrate Kotlin/JS code with existing tooling, to create
hybrid applications and leverage code-sharing functionality in multiplatform projects.
Learn more about the available features in the Kotlin/JS IR compiler backend.
Kotlin/Native
In 1.4.0, Kotlin/Native got a significant number of new features and improvements, including:
Performance improvements
Support
for
Kotlin's
suspending
functions
in
Swift
and
Objective-C
In 1.4.0, we add the basic support for suspending functions in Swift and Objective-C. Now, when you compile a Kotlin module into an
Apple framework, suspending functions are available in it as functions with callbacks (completionHandler in the Swift/Objective-C
terminology). When you have such functions in the generated framework's header, you can call them from your Swift or Objective-C code
and even override them.
204
Objective-C
generics
support
by
default
Previous versions of Kotlin provided experimental support for generics in Objective-C interop. Since 1.4.0, Kotlin/Native generates Apple
frameworks with generics from Kotlin code by default. In some cases, this may break existing Objective-C or Swift code calling Kotlin
frameworks. To have the framework header written without generics, add the -Xno-objc-generics compiler option.
kotlin {
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
binaries.all {
freeCompilerArgs += "-Xno-objc-generics"
}
}
}
Please note that all specifics and limitations listed in the documentation on interoperability with Objective-C are still valid.
Exception
handling
in
Objective-C/Swift
interop
In 1.4.0, we slightly change the Swift API generated from Kotlin with respect to the way exceptions are translated. There is a fundamental
difference in error handling between Kotlin and Swift. All Kotlin exceptions are unchecked, while Swift has only checked errors. Thus, to
make Swift code aware of expected exceptions, Kotlin functions should be marked with a @Throws annotation specifying a list of
potential exception classes.
When compiling to Swift or the Objective-C framework, functions that have or are inheriting @Throws annotation are represented as
NSError*-producing methods in Objective-C and as throws methods in Swift.
Previously, any exceptions other than RuntimeException and Error were propagated as NSError. Now this behavior changes: now NSError
is thrown only for exceptions that are instances of classes specified as parameters of @Throws annotation (or their subclasses). Other
Kotlin exceptions that reach Swift/Objective-C are considered unhandled and cause program termination.
Generate
release
.dSYMs
on
Apple
targets
by
default
Starting with 1.4.0, the Kotlin/Native compiler produces debug symbol files (.dSYMs) for release binaries on Darwin platforms by default.
This can be disabled with the -Xadd-light-debug=disable compiler option. On other platforms, this option is disabled by default. To toggle
this option in Gradle, use:
kotlin {
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
binaries.all {
freeCompilerArgs += "-Xadd-light-debug={enable|disable}"
}
}
}
Performance
improvements
Kotlin/Native has received a number of performance improvements that speed up both the development process and execution. Here are
some examples:
To improve the speed of object allocation, we now offer the mimalloc memory allocator as an alternative to the system allocator.
mimalloc works up to two times faster on some benchmarks. Currently, the usage of mimalloc in Kotlin/Native is experimental; you can
switch to it using the -Xallocator=mimalloc compiler option.
We've reworked how C interop libraries are built. With the new tooling, Kotlin/Native produces interop libraries up to 4 times as fast as
205
before, and artifacts are 25% to 30% the size they used to be.
Overall runtime performance has improved because of optimizations in GC. This improvement will be especially apparent in projects
with a large number of long-lived objects. HashMap and HashSet collections now work faster by escaping redundant boxing.
In 1.3.70 we introduced two new features for improving the performance of Kotlin/Native compilation: caching project dependencies
and running the compiler from the Gradle daemon. Since that time, we've managed to fix numerous issues and improve the overall
stability of these features.
Simplified
management
of
CocoaPods
dependencies
Previously, once you integrated your project with the dependency manager CocoaPods, you could build an iOS, macOS, watchOS, or
tvOS part of your project only in Xcode, separate from other parts of your multiplatform project. These other parts could be built in IntelliJ
IDEA.
Moreover, every time you added a dependency on an Objective-C library stored in CocoaPods (Pod library), you had to switch from IntelliJ
IDEA to Xcode, call pod install, and run the Xcode build there.
Now you can manage Pod dependencies right in IntelliJ IDEA while enjoying the benefits it provides for working with code, such as code
highlighting and completion. You can also build the whole Kotlin project with Gradle, without having to switch to Xcode. This means you
only have to go to Xcode when you need to write Swift/Objective-C code or run your application on a simulator or device.
Now you can also work with Pod libraries stored locally.
A Kotlin project and Pod libraries stored remotely in the CocoaPods repository or stored locally on your machine.
A Kotlin Pod (Kotlin project used as a CocoaPods dependency) and an Xcode project with one or more targets.
Complete the initial configuration, and when you add a new dependency to cocoapods, just re-import the project in IntelliJ IDEA. The new
dependency will be added automatically. No additional steps are required.
Kotlin
Multiplatform
Support for multiplatform projects is in Alpha. It may change incompatibly and require manual migration in the future. We
appreciate your feedback on it in YouTrack.
Kotlin Multiplatform reduces time spent writing and maintaining the same code for different platforms while retaining the flexibility and
benefits of native programming. We continue investing our effort in multiplatform features and improvements:
206
Sharing
code
in
several
targets
with
the
hierarchical
project
structure
With the new hierarchical project structure support, you can share code among several platforms in a multiplatform project.
Previously, any code added to a multiplatform project could be placed either in a platform-specific source set, which is limited to one
target and can't be reused by any other platform, or in a common source set, like commonMain or commonTest, which is shared across
all the platforms in the project. In the common source set, you could only call a platform-specific API by using an expect declaration that
needs platform-specific actual implementations.
This made it easy to share code on all platforms, but it was not so easy to share between only some of the targets, especially similar ones
that could potentially reuse a lot of the common logic and third-party APIs.
For example, in a typical multiplatform project targeting iOS, there are two iOS-related targets: one for iOS ARM64 devices, and the other
for the x64 simulator. They have separate platform-specific source sets, but in practice, there is rarely a need for different code for the
device and simulator, and their dependencies are much alike. So iOS-specific code could be shared between them.
Apparently, in this setup, it would be desirable to have a shared source set for two iOS targets, with Kotlin/Native code that could still
directly call any of the APIs that are common to both the iOS device and the simulator.
Now you can do this with the hierarchical project structure support, which infers and adapts the API and language features available in
each source set based on which targets consume them.
For common combinations of targets, you can create a hierarchical structure with target shortcuts.
For example, create two iOS targets and the shared source set shown above with the ios() shortcut:
207
kotlin {
ios() // iOS device and simulator targets; iosMain and iosTest source sets
}
For other combinations of targets, by connecting the source sets with the dependsOn relation.
Hierarchical structure
Kotlin
kotlin{
sourceSets {
val desktopMain by creating {
dependsOn(commonMain)
}
val linuxX64Main by getting {
dependsOn(desktopMain)
}
val mingwX64Main by getting {
dependsOn(desktopMain)
}
val macosX64Main by getting {
dependsOn(desktopMain)
}
}
}
Groovy
kotlin {
sourceSets {
desktopMain {
208
dependsOn(commonMain)
}
linuxX64Main {
dependsOn(desktopMain)
}
mingwX64Main {
dependsOn(desktopMain)
}
macosX64Main {
dependsOn(desktopMain)
}
}
}
Thanks to the hierarchical project structure, libraries can also provide common APIs for a subset of targets. Learn more about sharing
code in libraries.
Leveraging
native
libs
in
the
hierarchical
structure
You can use platform-dependent libraries, such as Foundation, UIKit, and POSIX, in source sets shared among several native targets. This
can help you share more native code without being limited by platform-specific dependencies.
No additional steps are required – everything is done automatically. IntelliJ IDEA will help you detect common declarations that you can
use in the shared code.
Specifying
dependencies
only
once
From now on, instead of specifying dependencies on different variants of the same library in shared and platform-specific source sets
where it is used, you should specify a dependency only once in the shared source set.
Kotlin
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
}
}
}
}
Groovy
kotlin {
sourceSets {
commonMain {
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
}
}
}
}
209
Don't use kotlinx library artifact names with suffixes specifying the platform, such as -common, -native, or similar, as they are NOT
supported anymore. Instead, use the library base artifact name, which in the example above is kotlinx-coroutines-core.
The stdlib library – starting from Kotlin 1.4.0, the stdlib dependency is added automatically.
The kotlin.test library – you should still use test-common and test-annotations-common. These dependencies will be addressed later.
If you need a dependency only for a specific platform, you can still use platform-specific variants of standard and kotlinx libraries with
such suffixes as -jvm or-js, for example kotlinx-coroutines-core-jvm.
Gradle
project
improvements
Besides Gradle project features and improvements that are specific to Kotlin Multiplatform, Kotlin/JVM, Kotlin/Native, and Kotlin/JS, there
are several changes applicable to all Kotlin Gradle projects:
Dependency
on
the
standard
library
added
by
default
You no longer need to declare a dependency on the stdlib library in any Kotlin Gradle project, including a multiplatform one. The
dependency is added by default.
The automatically added standard library will be the same version of the Kotlin Gradle plugin, since they have the same versioning.
For platform-specific source sets, the corresponding platform-specific variant of the library is used, while a common standard library is
added to the rest. The Kotlin Gradle plugin will select the appropriate JVM standard library depending on the kotlinOptions.jvmTarget
compiler option of your Gradle build script.
Minimum
Gradle
version
for
Kotlin
projects
To enjoy the new features in your Kotlin projects, update Gradle to the latest version. Multiplatform projects require Gradle 6.0 or later,
while other Kotlin projects work with Gradle 5.4 or later.
Improved
*.gradle.kts
support
in
the
IDE
In 1.4.0, we continued improving the IDE support for Gradle Kotlin DSL scripts (*.gradle.kts files). Here is what the new version brings:
Explicit loading of script configurations for better performance. Previously, the changes you make to the build script were loaded
automatically in the background. To improve the performance, we've disabled the automatic loading of build script configuration in
1.4.0. Now the IDE loads the changes only when you explicitly apply them.
In Gradle versions earlier than 6.0, you need to manually load the script configuration by clicking Load Configuration in the editor.
210
*.gradle.kts – Load Configuration
In Gradle 6.0 and above, you can explicitly apply changes by clicking Load Gradle Changes or by reimporting the Gradle project.
We've added one more action in IntelliJ IDEA 2020.1 with Gradle 6.0 and above – Load Script Configurations, which loads changes to
the script configurations without updating the whole project. This takes much less time than reimporting the whole project.
You should also Load Script Configurations for newly created scripts or when you open a project with new Kotlin plugin for the first
time.
With Gradle 6.0 and above, you are now able to load all scripts at once as opposed to the previous implementation where they were
loaded individually. Since each request requires the Gradle configuration phase to be executed, this could be resource-intensive for
large Gradle projects.
Currently, such loading is limited to build.gradle.kts and settings.gradle.kts files (please vote for the related issue). To enable
highlighting for init.gradle.kts or applied script plugins, use the old mechanism – adding them to standalone scripts. Configuration for
that scripts will be loaded separately when you need it. You can also enable auto-reload for such scripts.
Better error reporting. Previously you could only see errors from the Gradle Daemon in separate log files. Now the Gradle Daemon
returns all the information about errors directly and shows it in the Build tool window. This saves you both time and effort.
211
Standard
library
Here is the list of the most significant changes to the Kotlin standard library in 1.4.0:
Bit operations
Deprecations
Common
exception
processing
API
The following API elements have been moved to the common library:
Throwable.stackTraceToString() extension function, which returns the detailed description of this throwable with its stack trace, and
Throwable.printStackTrace(), which prints this description to the standard error output.
Throwable.addSuppressed() function, which lets you specify the exceptions that were suppressed in order to deliver the exception, and
the Throwable.suppressedExceptions property, which returns a list of all the suppressed exceptions.
@Throws annotation, which lists exception types that will be checked when the function is compiled to a platform method (on JVM or
native platforms).
New
functions
for
arrays
and
collections
Collections
In 1.4.0, the standard library includes a number of useful functions for working with collections:
setOfNotNull(), which makes a set consisting of all the non-null items among the provided arguments.
fun main() {
//sampleStart
val set = setOfNotNull(null, 1, 2, 0, null)
println(set)
//sampleEnd
}
fun main() {
212
//sampleStart
val numbers = (0 until 50).asSequence()
val result = numbers.map { it * 2 }.shuffled().take(5)
println(result.toList()) //five random even numbers below 100
//sampleEnd
}
*Indexed() counterparts for onEach() and flatMap(). The operation that they apply to the collection elements has the element index as a
parameter.
fun main() {
//sampleStart
listOf("a", "b", "c", "d").onEachIndexed {
index, item -> println(index.toString() + ":" + item)
}
*OrNull() counterparts randomOrNull(), reduceOrNull(), and reduceIndexedOrNull(). They return null on empty collections.
fun main() {
//sampleStart
val empty = emptyList<Int>()
empty.reduceOrNull { a, b -> a + b }
//empty.reduce { a, b -> a + b } // Exception: Empty collection can't be reduced.
//sampleEnd
}
runningFold(), its synonym scan(), and runningReduce() apply the given operation to the collection elements sequentially, similarly
tofold() and reduce(); the difference is that these new functions return the whole sequence of intermediate results.
fun main() {
//sampleStart
val numbers = mutableListOf(0, 1, 2, 3, 4, 5)
val runningReduceSum = numbers.runningReduce { sum, item -> sum + item }
val runningFoldSum = numbers.runningFold(10) { sum, item -> sum + item }
//sampleEnd
println(runningReduceSum.toString())
println(runningFoldSum.toString())
}
sumOf() takes a selector function and returns a sum of its values for all elements of a collection. sumOf() can produce sums of the types
Int, Long, Double, UInt, and ULong. On the JVM, BigInteger and BigDecimal are also available.
data class OrderItem(val name: String, val price: Double, val count: Int)
fun main() {
//sampleStart
val order = listOf<OrderItem>(
OrderItem("Cake", price = 10.0, count = 1),
OrderItem("Coffee", price = 2.5, count = 3),
OrderItem("Tea", price = 1.5, count = 2))
213
//sampleEnd
println("You've ordered $count items that cost $total in total")
}
The min() and max() functions have been renamed to minOrNull() and maxOrNull() to comply with the naming convention used across
the Kotlin collections API. An *OrNull suffix in the function name means that it returns null if the receiver collection is empty. The same
applies to minBy(), maxBy(), minWith(), maxWith() – in 1.4, they have *OrNull() synonyms.
The new minOf() and maxOf() extension functions return the minimum and the maximum value of the given selector function on the
collection items.
data class OrderItem(val name: String, val price: Double, val count: Int)
fun main() {
//sampleStart
val order = listOf<OrderItem>(
OrderItem("Cake", price = 10.0, count = 1),
OrderItem("Coffee", price = 2.5, count = 3),
OrderItem("Tea", price = 1.5, count = 2))
val highestPrice = order.maxOf { it.price }
//sampleEnd
println("The most expensive item in the order costs $highestPrice")
}
There are also minOfWith() and maxOfWith(), which take a Comparator as an argument, and *OrNull() versions of all four functions that
return null on empty collections.
New overloads for flatMap and flatMapTo let you use transformations with return types that don't match the receiver type, namely:
fun main() {
//sampleStart
val list = listOf("kot", "lin")
val lettersList = list.flatMap { it.asSequence() }
val lettersSeq = list.asSequence().flatMap { it.toList() }
//sampleEnd
println(lettersList)
println(lettersSeq.toList())
}
removeFirst() and removeLast() shortcuts for removing elements from mutable lists, and *orNull() counterparts of these functions.
Arrays
To provide a consistent experience when working with different container types, we've also added new functions for arrays:
onEach() performs the given action on each array element and returns the array itself.
associateWith() and associateWithTo() build maps with the array elements as keys.
reverse() for array subranges reverses the order of the elements in the subrange.
sortDescending() for array subranges sorts the elements in the subrange in descending order.
sort() and sortWith() for array subranges are now available in the common library.
214
fun main() {
//sampleStart
var language = ""
val letters = arrayOf("k", "o", "t", "l", "i", "n")
val fileExt = letters.onEach { language += it }
.filterNot { it in "aeuio" }.take(2)
.joinToString(prefix = ".", separator = "")
println(language) // "kotlin"
println(fileExt) // ".kt"
letters.shuffle()
letters.reverse(0, 3)
letters.sortDescending(2, 5)
println(letters.contentToString()) // [k, o, t, l, i, n]
//sampleEnd
}
Additionally, there are new functions for conversions between CharArray/ByteArray and String:
fun main() {
//sampleStart
val str = "kotlin"
val array = str.toCharArray()
println(array.concatToString())
//sampleEnd
}
ArrayDeque
We've also added the ArrayDeque class – an implementation of a double-ended queue. Double-ended queue lets you can add or remove
elements both at the beginning and the end of the queue in an amortized constant time. You can use a double-ended queue by default
when you need a queue or a stack in your code.
fun main() {
val deque = ArrayDeque(listOf(1, 2, 3))
deque.addFirst(0)
deque.addLast(4)
println(deque) // [0, 1, 2, 3, 4]
println(deque.first()) // 0
println(deque.last()) // 4
deque.removeFirst()
deque.removeLast()
println(deque) // [1, 2, 3]
}
The 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.
Functions
for
string
manipulations
The standard library in 1.4.0 includes a number of improvements in the API for string manipulation:
StringBuilder has useful new extension functions: set(), setRange(), deleteAt(), deleteRange(), appendRange(), and others.
215
fun main() {
//sampleStart
val sb = StringBuilder("Bye Kotlin 1.3.72")
sb.deleteRange(0, 3)
sb.insertRange(0, "Hello", 0 ,5)
sb.set(15, '4')
sb.setRange(17, 19, "0")
print(sb.toString())
//sampleEnd
}
Some existing functions of StringBuilder are available in the common library. Among them are append(), insert(), substring(), setLength(),
and more.
New functions Appendable.appendLine() and StringBuilder.appendLine() have been added to the common library. They replace the
JVM-only appendln() functions of these classes.
fun main() {
//sampleStart
println(buildString {
appendLine("Hello,")
appendLine("world")
})
//sampleEnd
}
Bit
operations
New functions for bit manipulations:
countOneBits()
countLeadingZeroBits()
countTrailingZeroBits()
takeHighestOneBit()
takeLowestOneBit()
fun main() {
//sampleStart
val number = "1010000".toInt(radix = 2)
println(number.countOneBits())
println(number.countTrailingZeroBits())
println(number.takeHighestOneBit().toString(2))
//sampleEnd
}
Delegated
properties
improvements
In 1.4.0, we have added new features to improve your experience with delegated properties in Kotlin:
216
ReadWriteProperty now extends ReadOnlyProperty so you can use both of them for read-only properties.
Aside from the new API, we've made some optimizations that reduce the resulting bytecode size. These optimizations are described in this
blog post.
Converting
from
KType
to
Java
Type
A new extension property KType.javaType (currently experimental) in the stdlib helps you obtain a java.lang.reflect.Type from a Kotlin type
without using the whole kotlin-reflect dependency.
import kotlin.reflect.javaType
import kotlin.reflect.typeOf
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T> accessReifiedTypeArg() {
val kType = typeOf<T>()
println("Kotlin type: $kType")
println("Java type: ${kType.javaType}")
}
@OptIn(ExperimentalStdlibApi::class)
fun main() {
accessReifiedTypeArg<String>()
// Kotlin type: kotlin.String
// Java type: class java.lang.String
accessReifiedTypeArg<List<String>>()
// Kotlin type: kotlin.collections.List<kotlin.String>
// Java type: java.util.List<java.lang.String>
}
Proguard
configurations
for
Kotlin
reflection
Starting from 1.4.0, we have embedded Proguard/R8 configurations for Kotlin Reflection in kotlin-reflect.jar. With this in place, most
Android projects using R8 or Proguard should work with kotlin-reflect without needing any additional configuration. You no longer need to
copy-paste the Proguard rules for kotlin-reflect internals. But note that you still need to explicitly list all the APIs you're going to reflect on.
Improving
the
existing
API
Several functions now work on null receivers, for example:
toBoolean() on strings
NaN, NEGATIVE_INFINITY, and POSITIVE_INFINITY in Double and Float are now defined as const, so you can use them as annotation
arguments.
New constants SIZE_BITS and SIZE_BYTES in Double and Float contain the number of bits and bytes used to represent an instance of
the type in binary form.
The maxOf() and minOf() top-level functions can accept a variable number of arguments ( vararg).
module-info
descriptors
for
stdlib
artifacts
Kotlin 1.4.0 adds module-info.java module information to default standard library artifacts. This lets you use them with jlink tool, which
217
generates custom Java runtime images containing only the platform modules that are required for your app. You could already use jlink
with Kotlin standard library artifacts, but you had to use separate artifacts to do so – the ones with the "modular" classifier – and the whole
setup wasn't straightforward.
In Android, make sure you use the Android Gradle plugin version 3.2 or higher, which can correctly process jar files with module-info.
Deprecations
To convert floating-point numbers to Byte or Short, use the two-step conversion: first, convert them to Int, and then convert them again to
the target type.
Exclusion
of
the
deprecated
experimental
coroutines
The kotlin.coroutines.experimental API was deprecated in favor of kotlin.coroutines in 1.3.0. In 1.4.0, we're completing the deprecation
cycle for kotlin.coroutines.experimental by removing it from the standard library. For those who still use it on the JVM, we've provided a
compatibility artifact kotlin-coroutines-experimental-compat.jar with all the experimental coroutines APIs. We've published it to Maven,
and we include it in the Kotlin distribution alongside the standard library.
Stable
JSON
serialization
With Kotlin 1.4.0, we are shipping the first stable version of kotlinx.serialization - 1.0.0-RC. Now we are pleased to declare the JSON
serialization API in kotlinx-serialization-core (previously known as kotlinx-serialization-runtime) stable. Libraries for other serialization
formats remain experimental, along with some advanced parts of the core library.
We have significantly reworked the API for JSON serialization to make it more consistent and easier to use. From now on, we'll continue
developing the JSON serialization API in a backward-compatible manner. However, if you have used previous versions of it, you'll need to
rewrite some of your code when migrating to 1.0.0-RC. To help you with this, we also offer the Kotlin Serialization Guide – the complete set
of documentation for kotlinx.serialization. It will guide you through the process of using the most important features and it can help you
address any issues that you might face.
Note: kotlinx-serialization 1.0.0-RC only works with Kotlin compiler 1.4. Earlier compiler versions are not compatible.
Scripting
and
REPL
In 1.4.0, scripting in Kotlin benefits from a number of functional and performance improvements along with other updates. Here are some
218
of the key changes:
Artifacts renaming
To help you become more familiar with scripting in Kotlin, we've prepared a project with examples. It contains examples of the standard
scripts (*.main.kts) and examples of uses of the Kotlin Scripting API and custom script definitions. Please give it a try and share your
feedback using our issue tracker.
New
dependencies
resolution
API
In 1.4.0, we've introduced a new API for resolving external dependencies (such as Maven artifacts), along with implementations for it. This
API is published in the new artifacts kotlin-scripting-dependencies and kotlin-scripting-dependencies-maven. The previous dependency
resolution functionality in kotlin-script-util library is now deprecated.
New
REPL
API
The new experimental REPL API is now a part of the Kotlin Scripting API. There are also several implementations of it in the published
artifacts, and some have advanced functionality, such as code completion. We use this API in the Kotlin Jupyter kernel and now you can
try it in your own custom shells and REPLs.
Compiled
scripts
cache
The Kotlin Scripting API now provides the ability to implement a compiled scripts cache, significantly speeding up subsequent executions
of unchanged scripts. Our default advanced script implementation kotlin-main-kts already has its own cache.
Artifacts
renaming
In order to avoid confusion about artifact names, we've renamed kotlin-scripting-jsr223-embeddable and kotlin-scripting-jvm-host-
embeddable to just kotlin-scripting-jsr223 and kotlin-scripting-jvm-host. These artifacts depend on the kotlin-compiler-embeddable
artifact, which shades the bundled third-party libraries to avoid usage conflicts. With this renaming, we're making the usage of kotlin-
compiler-embeddable (which is safer in general) the default for scripting artifacts. If, for some reason, you need artifacts that depend on
the unshaded kotlin-compiler, use the artifact versions with the -unshaded suffix, such as kotlin-scripting-jsr223-unshaded. Note that this
renaming affects only the scripting artifacts that are supposed to be used directly; names of other artifacts remain unchanged.
Migrating
to
Kotlin
1.4.0
The Kotlin plugin's migration tools help you migrate your projects from earlier versions of Kotlin to 1.4.0.
Just change the Kotlin version to 1.4.0 and re-import your Gradle or Maven project. The IDE will then ask you about migration.
If you agree, it will run migration code inspections that will check your code and suggest corrections for anything that doesn't work or that
is not recommended in 1.4.0.
219
Run migration
Code inspections have different severity levels, to help you decide which suggestions to accept and which to ignore.
Migration inspections
Kotlin 1.4.0 is a feature release and therefore can bring incompatible changes to the language. Find the detailed list of such changes in the
Compatibility Guide for Kotlin 1.4.
What's
new
in
Kotlin
1.3
Release date: 29 October 2018
Coroutines
release
After some long and extensive battle testing, coroutines are now released! It means that from Kotlin 1.3 the language support and the API
are fully stable. Check out the new coroutines overview page.
Kotlin 1.3 introduces callable references on suspend-functions and support of coroutines in the reflection API.
Kotlin/Native
Kotlin 1.3 continues to improve and polish the Native target. See the Kotlin/Native overview for details.
Multiplatform
projects
In 1.3, we've completely reworked the model of multiplatform projects in order to improve expressiveness and flexibility, and to make
sharing common code easier. Also, Kotlin/Native is now supported as one of the targets!
220
The key differences to the old model are:
In the old model, common and platform-specific code needed to be placed in separate modules, linked by expectedBy dependencies.
Now, common and platform-specific code is placed in different source roots of the same module, making projects easier to configure.
There is now a large number of preset platform configurations for different supported platforms.
The dependencies configuration has been changed; dependencies are now specified separately for each source root.
Source sets can now be shared between an arbitrary subset of platforms (for example, in a module that targets JS, Android and iOS,
you can have a source set that is shared only between Android and iOS).
Contracts
The Kotlin compiler does extensive static analysis to provide warnings and reduce boilerplate. One of the most notable features is
smartcasts — with the ability to perform a cast automatically based on the performed type checks:
However, as soon as these checks are extracted in a separate function, all the smartcasts immediately disappear:
To improve the behavior in such cases, Kotlin 1.3 introduces experimental mechanism called contracts.
Contracts allow a function to explicitly describe its behavior in a way which is understood by the compiler. Currently, two wide classes of
cases are supported:
Improving smartcasts analysis by declaring the relation between a function's call outcome and the passed arguments values:
221
// It tells the compiler:
// "This function will invoke 'block' here and now, and exactly one time"
contract { callsInPlace(block, EXACTLY_ONCE) }
}
fun foo() {
val x: Int
synchronize(lock) {
x = 42 // Compiler knows that lambda passed to 'synchronize' is called
// exactly once, so no reassignment is reported
}
println(x) // Compiler knows that lambda will be definitely called, performing
// initialization, so 'x' is considered to be initialized here
}
Contracts
in
stdlib
stdlib already makes use of contracts, which leads to improvements in the analyses described above. This part of contracts is stable,
meaning that you can benefit from the improved analysis right now without any additional opt-ins:
//sampleStart
fun bar(x: String?) {
if (!x.isNullOrEmpty()) {
println("length of '$x' is ${x.length}") // Yay, smartcast to not-null!
}
}
//sampleEnd
fun main() {
bar(null)
bar("42")
}
Custom
contracts
It is possible to declare contracts for your own functions, but this feature is experimental, as the current syntax is in a state of early
prototype and will most probably be changed. Also please note that currently the Kotlin compiler does not verify contracts, so it's the
responsibility of the programmer to write correct and sound contracts.
Custom contracts are introduced by a call to contract stdlib function, which provides DSL scope:
See the details on the syntax as well as the compatibility notice in the KEEP.
Capturing
when
subject
in
a
variable
In Kotlin 1.3, it is now possible to capture the when subject into a variable:
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
222
While it was already possible to extract this variable just before when, val in when has its scope properly restricted to the body of when,
and so preventing namespace pollution. See the full documentation on when here.
@JvmStatic
and
@JvmField
in
companions
of
interfaces
With Kotlin 1.3, it is possible to mark members of a companion object of interfaces with annotations @JvmStatic and @JvmField. In the
classfile, such members will be lifted to the corresponding interface and marked as static.
interface Foo {
companion object {
@JvmField
val answer: Int = 42
@JvmStatic
fun sayHello() {
println("Hello, world!")
}
}
}
interface Foo {
public static int answer = 42;
public static void sayHello() {
// ...
}
}
Nested
declarations
in
annotation
classes
In Kotlin 1.3, it is possible for annotations to have nested classes, interfaces, objects, and companions:
companion object {
fun foo(): Int = 42
val bar: Int = 42
}
}
Parameterless
main
By convention, the entry point of a Kotlin program is a function with a signature like main(args: Array<String>), where args represent the
command-line arguments passed to the program. However, not every application supports command-line arguments, so this parameter
often ends up not being used.
Kotlin 1.3 introduced a simpler form of main which takes no parameters. Now "Hello, World" in Kotlin is 19 characters shorter!
223
fun main() {
println("Hello, world!")
}
Functions
with
big
arity
In Kotlin, functional types are represented as generic classes taking a different number of parameters: Function0<R>, Function1<P0, R>,
Function2<P0, P1, R>, ... This approach has a problem in that this list is finite, and it currently ends with Function22.
Kotlin 1.3 relaxes this limitation and adds support for functions with bigger arity:
fun trueEnterpriseComesToKotlin(block: (Any, Any, ... /* 42 more */, Any) -> Any) {
block(Any(), Any(), ..., Any())
}
Progressive
mode
Kotlin cares a lot about stability and backward compatibility of code: Kotlin compatibility policy says that breaking changes (e.g., a change
which makes the code that used to compile fine, not compile anymore) can be introduced only in the major releases (1.2, 1.3, etc.).
We believe that a lot of users could use a much faster cycle where critical compiler bug fixes arrive immediately, making the code more
safe and correct. So, Kotlin 1.3 introduces the progressive compiler mode, which can be enabled by passing the argument -progressive to
the compiler.
In the progressive mode, some fixes in language semantics can arrive immediately. All these fixes have two important properties:
They preserve backward compatibility of source code with older compilers, meaning that all the code which is compilable by the
progressive compiler will be compiled fine by non-progressive one.
They only make code safer in some sense — e.g., some unsound smartcast can be forbidden, behavior of the generated code may be
changed to be more predictable/stable, and so on.
Enabling the progressive mode can require you to rewrite some of your code, but it shouldn't be too much — all the fixes enabled under
progressive are carefully handpicked, reviewed, and provided with tooling migration assistance. We expect that the progressive mode will
be a nice choice for any actively maintained codebases which are updated to the latest language versions quickly.
Inline
classes
Inline classes are in Alpha. They may change incompatibly and require manual migration in the future. We appreciate your
feedback on it in YouTrack. See details in the reference.
Kotlin 1.3 introduces a new kind of declaration — inline class. Inline classes can be viewed as a restricted version of the usual classes, in
particular, inline classes must have exactly one property:
The Kotlin compiler will use this restriction to aggressively optimize runtime representation of inline classes and substitute their instances
224
with the value of the underlying property where possible removing constructor calls, GC pressure, and enabling other optimizations:
Unsigned
integers
Unsigned integers are in Beta. Their implementation is almost stable, but migration steps may be required in the future. We'll do
our best to minimize any changes you will have to make.
Most of the functionality of signed types are supported for unsigned counterparts too:
fun main() {
//sampleStart
// You can define unsigned types using literal suffixes
val uint = 42u
val ulong = 42uL
val ubyte: UByte = 255u
// You can convert signed types to unsigned and vice versa via stdlib extensions:
val int = uint.toInt()
val byte = ubyte.toByte()
val ulong2 = byte.toULong()
@JvmDefault
225
@JvmDefault is Experimental. It may be dropped or changed at any time. Use it only for evaluation purposes. We appreciate
your feedback on it in YouTrack.
Kotlin targets a wide range of the Java versions, including Java 6 and Java 7, where default methods in the interfaces are not allowed. For
your convenience, the Kotlin compiler works around that limitation, but this workaround isn't compatible with the default methods,
introduced in Java 8.
This could be an issue for Java-interoperability, so Kotlin 1.3 introduces the @JvmDefault annotation. Methods annotated with this
annotation will be generated as default methods for JVM:
interface Foo {
// Will be generated as 'default' method
@JvmDefault
fun foo(): Int = 42
}
Warning! Annotating your API with @JvmDefault has serious implications on binary compatibility. Make sure to carefully read the
reference page before using @JvmDefault in production.
Standard
library
Multiplatform
random
Prior to Kotlin 1.3, there was no uniform way to generate random numbers on all platforms — we had to resort to platform-specific
solutions like java.util.Random on JVM. This release fixes this issue by introducing the class kotlin.random.Random, which is available on
all platforms:
import kotlin.random.Random
fun main() {
//sampleStart
val number = Random.nextInt(42) // number is in range [0, limit)
println(number)
//sampleEnd
}
isNullOrEmpty
and
orEmpty
extensions
isNullOrEmpty and orEmpty extensions for some types are already present in stdlib. The first one returns true if the receiver is null or
empty, and the second one falls back to an empty instance if the receiver is null. Kotlin 1.3 provides similar extensions on collections,
maps, and arrays of objects.
Copy
elements
between
two
existing
arrays
The array.copyInto(targetArray, targetOffset, startIndex, endIndex) functions for the existing array types, including the unsigned arrays,
make it easier to implement array-based containers in pure Kotlin.
fun main() {
//sampleStart
val sourceArr = arrayOf("k", "o", "t", "l", "i", "n")
226
val targetArr = sourceArr.copyInto(arrayOfNulls<String>(6), 3, startIndex = 3, endIndex = 6)
println(targetArr.contentToString())
sourceArr.copyInto(targetArr, startIndex = 0, endIndex = 3)
println(targetArr.contentToString())
//sampleEnd
}
associateWith
It is quite a common situation to have a list of keys and want to build a map by associating each of these keys with some value. It was
possible to do it before with the associate { it to getValue(it) } function, but now we're introducing a more efficient and easy to explore
alternative: keys.associateWith { getValue(it) }.
fun main() {
//sampleStart
val keys = 'a'..'f'
val map = keys.associateWith { it.toString().repeat(5).capitalize() }
map.forEach { println(it) }
//sampleEnd
}
ifEmpty
and
ifBlank
functions
Collections, maps, object arrays, char sequences, and sequences now have an ifEmpty function, which allows specifying a fallback value
that will be used instead of the receiver if it is empty:
fun main() {
//sampleStart
fun printAllUppercase(data: List<String>) {
val result = data
.filter { it.all { c -> c.isUpperCase() } }
.ifEmpty { listOf("<no uppercase>") }
result.forEach { println(it) }
}
printAllUppercase(listOf("foo", "Bar"))
printAllUppercase(listOf("FOO", "BAR"))
//sampleEnd
}
Char sequences and strings in addition have an ifBlank extension that does the same thing as ifEmpty but checks for a string being all
whitespace instead of empty.
fun main() {
//sampleStart
val s = " \n"
println(s.ifBlank { "<blank>" })
println(s.ifBlank { null })
//sampleEnd
}
Sealed
classes
in
reflection
We've added a new API to kotlin-reflect that can be used to enumerate all the direct subtypes of a sealed class, namely
KClass.sealedSubclasses.
227
Smaller
changes
Tooling
Code
style
support
in
IDE
Kotlin 1.3 introduces support for the recommended code style in IntelliJ IDEA. Check out this page for the migration guidelines.
kotlinx.serialization
kotlinx.serialization is a library which provides multiplatform support for (de)serializing objects in Kotlin. Previously, it was a separate
project, but since Kotlin 1.3, it ships with the Kotlin compiler distribution on par with the other compiler plugins. The main difference is that
you don't need to manually watch out for the Serialization IDE Plugin being compatible with the Kotlin IDE plugin version you're using: now
the Kotlin IDE plugin already includes serialization!
Even though kotlinx.serialization now ships with the Kotlin Compiler distribution, it is still considered to be an experimental
feature in Kotlin 1.3.
Scripting
update
Scripting is Experimental. It may be dropped or changed at any time. Use it only for evaluation purposes. We appreciate your
feedback on it in YouTrack.
Kotlin 1.3 continues to evolve and improve scripting API, introducing some experimental support for scripts customization, such as adding
external properties, providing static or dynamic dependencies, and so on.
Scratches
support
Kotlin 1.3 introduces support for runnable Kotlin scratch files. Scratch file is a kotlin script file with the .kts extension that you can run and
get evaluation results directly in the editor.
What's
new
in
Kotlin
1.2
228
Release date: 28 November 2017
Table
of
contents
Multiplatform projects
Standard library
JVM backend
JavaScript backend
Multiplatform
projects
(experimental)
Multiplatform projects are a new experimental feature in Kotlin 1.2, allowing you to reuse code between target platforms supported by
Kotlin – JVM, JavaScript, and (in the future) Native. In a multiplatform project, you have three kinds of modules:
A common module contains code that is not specific to any platform, as well as declarations without implementation of platform-
dependent APIs.
A platform module contains implementations of platform-dependent declarations in the common module for a specific platform, as well
as other platform-dependent code.
A regular module targets a specific platform and can either be a dependency of platform modules or depend on platform modules.
When you compile a multiplatform project for a specific platform, the code for both the common and platform-specific parts is generated.
A key feature of the multiplatform project support is the possibility to express dependencies of common code on platform-specific parts
through expected and actual declarations. An expected declaration specifies an API (class, interface, annotation, top-level declaration
etc.). An actual declaration is either a platform-dependent implementation of the API or a typealias referring to an existing implementation
of the API in an external library. Here's an example:
fun greet() {
// usage of the expected API:
val greeting = hello("multiplatform world")
println(greeting)
}
229
See the multiplatform programming documentation for details and steps to build a multiplatform project.
Other
language
features
Array
literals
in
annotations
Starting with Kotlin 1.2, array arguments for annotations can be passed with the new array literal syntax instead of the arrayOf function:
Lateinit
top-level
properties
and
local
variables
The lateinit modifier can now be used on top-level properties and local variables. The latter can be used, for example, when a lambda
passed as a constructor argument to one object refers to another object which has to be defined later:
Check
whether
a
lateinit
var
is
initialized
You can now check whether a lateinit var has been initialized using isInitialized on the property reference:
class Foo {
lateinit var lateinitVar: String
fun initializationLogic() {
//sampleStart
println("isInitialized before assignment: " + this::lateinitVar.isInitialized)
lateinitVar = "value"
println("isInitialized after assignment: " + this::lateinitVar.isInitialized)
//sampleEnd
}
}
230
Inline
functions
with
default
functional
parameters
Inline functions are now allowed to have default values for their inlined functional parameters:
//sampleStart
inline fun <E> Iterable<E>.strings(transform: (E) -> String = { it.toString() }) =
map { transform(it) }
Information
from
explicit
casts
is
used
for
type
inference
The Kotlin compiler can now use information from type casts in type inference. If you're calling a generic method that returns a type
parameter T and casting the return value to a specific type Foo, the compiler now understands that T for this call needs to be bound to the
type Foo.
This is particularly important for Android developers, since the compiler can now correctly analyze generic findViewById calls in Android
API level 26:
Smart
cast
improvements
When a variable is assigned from a safe call expression and checked for null, the smart cast is now applied to the safe call receiver as
well:
Also, smart casts in a lambda are now allowed for local variables that are only modified before the lambda:
231
//sampleStart
val flag = args.size == 0
var x: String? = null
if (flag) x = "Yahoo!"
run {
if (x != null) {
println(x.length) // x is smart cast to String
}
}
//sampleEnd
}
Support
for
::foo
as
a
shorthand
for
this::foo
A bound callable reference to a member of this can now be written without explicit receiver, ::foo instead of this::foo. This also makes
callable references more convenient to use in lambdas where you refer to a member of the outer receiver.
Breaking
change:
sound
smart
casts
after
try
blocks
Earlier, Kotlin used assignments made inside a try block for smart casts after the block, which could break type- and null-safety and lead
to runtime failures. This release fixes this issue, making the smart casts more strict, but breaking some code that relied on such smart
casts.
To switch to the old smart casts behavior, pass the fallback flag -Xlegacy-smart-cast-after-try as the compiler argument. It will become
deprecated in Kotlin 1.3.
Deprecation:
data
classes
overriding
copy
When a data class derived from a type that already had the copy function with the same signature, the copy implementation generated for
the data class used the defaults from the supertype, leading to counter-intuitive behavior, or failed at runtime if there were no default
parameters in the supertype.
Inheritance that leads to a copy conflict has become deprecated with a warning in Kotlin 1.2 and will be an error in Kotlin 1.3.
Deprecation:
nested
types
in
enum
entries
Inside enum entries, defining a nested type that is not an inner class has been deprecated due to issues in the initialization logic. This
causes a warning in Kotlin 1.2 and will become an error in Kotlin 1.3.
Deprecation:
single
named
argument
for
vararg
For consistency with array literals in annotations, passing a single item for a vararg parameter in the named form (foo(items = i)) has been
deprecated. Please use the spread operator with the corresponding array factory functions:
foo(items = *arrayOf(1))
There is an optimization that removes redundant arrays creation in such cases, which prevents performance degradation. The single-
argument form produces warnings in Kotlin 1.2 and is to be dropped in Kotlin 1.3.
Deprecation:
inner
classes
of
generic
classes
extending
Throwable
Inner classes of generic types that inherit from Throwable could violate type-safety in a throw-catch scenario and thus have been
deprecated, with a warning in Kotlin 1.2 and an error in Kotlin 1.3.
232
Deprecation:
mutating
backing
field
of
a
read-only
property
Mutating the backing field of a read-only property by assigning field = ... in the custom getter has been deprecated, with a warning in
Kotlin 1.2 and an error in Kotlin 1.3.
Standard
library
Kotlin
standard
library
artifacts
and
split
packages
The Kotlin standard library is now fully compatible with the Java 9 module system, which forbids split packages (multiple jar files declaring
classes in the same package). In order to support that, new artifacts kotlin-stdlib-jdk7 and kotlin-stdlib-jdk8 are introduced, which replace
the old kotlin-stdlib-jre7 and kotlin-stdlib-jre8.
The declarations in the new artifacts are visible under the same package names from the Kotlin point of view, but have different package
names for Java. Therefore, switching to the new artifacts will not require any changes to your source code.
Another change made to ensure compatibility with the new module system is removing the deprecated declarations in the kotlin.reflect
package from the kotlin-reflect library. If you were using them, you need to switch to using the declarations in the kotlin.reflect.full
package, which is supported since Kotlin 1.1.
windowed,
chunked,
zipWithNext
New extensions for Iterable<T>, Sequence<T>, and CharSequence cover such use cases as buffering or batch processing ( chunked),
sliding window and computing sliding average (windowed) , and processing pairs of subsequent items (zipWithNext):
println("items: $items\n")
fill,
replaceAll,
shuffle/shuffled
A set of extension functions was added for manipulating lists: fill, replaceAll and shuffle for MutableList, and shuffled for read-only List:
233
items.fill(5)
println("Items filled with 5: $items")
//sampleEnd
}
Math
operations
in
kotlin-stdlib
Satisfying the longstanding request, Kotlin 1.2 adds the kotlin.math API for math operations that is common for JVM and JS and contains
the following:
Constants: PI and E
Trigonometric: cos, sin, tan and inverse of them: acos, asin, atan, atan2
Hyperbolic: cosh, sinh, tanh and their inverse: acosh, asinh, atanh
Rounding:
Binary representation:
The same set of functions (but without constants) is also available for Float arguments.
Operators
and
conversions
for
BigInteger
and
BigDecimal
Kotlin 1.2 introduces a set of functions for operating with BigInteger and BigDecimal and creating them from other numeric types. These
are:
Binary operators +, -, *, /, % and infix functions and, or, xor, shl, shr
234
Unary operators -, ++, --, and a function inv
Floating
point
to
bits
conversions
New functions were added for converting Double and Float to and from their bit representations:
toBits and toRawBits returning Long for Double and Int for Float
Double.fromBits and Float.fromBits for creating floating point numbers from the bit representation
Regex
is
now
serializable
The kotlin.text.Regex class has become Serializable and can now be used in serializable hierarchies.
Closeable.use
calls
Throwable.addSuppressed
if
available
The Closeable.use function calls Throwable.addSuppressed when an exception is thrown during closing the resource after some other
exception.
JVM
backend
Constructor
calls
normalization
Ever since version 1.0, Kotlin supported expressions with complex control flow, such as try-catch expressions and inline function calls.
Such code is valid according to the Java Virtual Machine specification. Unfortunately, some bytecode processing tools do not handle such
code quite well when such expressions are present in the arguments of constructor calls.
To mitigate this problem for the users of such bytecode processing tools, we've added a command-line compiler option ( -Xnormalize-
constructor-calls=MODE) that tells the compiler to generate more Java-like bytecode for such constructs. Here MODE is one of:
disable (default) – generate bytecode in the same way as in Kotlin 1.0 and 1.1.
enable – generate Java-like bytecode for constructor calls. This can change the order in which the classes are loaded and initialized.
preserve-class-initialization – generate Java-like bytecode for constructor calls, ensuring that the class initialization order is preserved.
This can affect overall performance of your application; use it only if you have some complex state shared between multiple classes and
updated on class initialization.
The "manual" workaround is to store the values of sub-expressions with control flow in variables, instead of evaluating them directly inside
the call arguments. It's similar to -Xnormalize-constructor-calls=enable.
Java-default
method
calls
Before Kotlin 1.2, interface members overriding Java-default methods while targeting JVM 1.6 produced a warning on super calls: Super
calls to Java default methods are deprecated in JVM target 1.6. Recompile with '-jvm-target 1.8'. In Kotlin 1.2, there's an error instead,
thus requiring any such code to be compiled with JVM target 1.8.
Breaking
change:
consistent
behavior
of
x.equals(null)
for
platform
types
Calling x.equals(null) on a platform type that is mapped to a Java primitive (Int!, Boolean!, Short!, Long!, Float!, Double!, Char!) incorrectly
returned true when x was null. Starting with Kotlin 1.2, calling x.equals(...) on a null value of a platform type throws an NPE (but x == ...
235
does not).
To return to the pre-1.2 behavior, pass the flag -Xno-exception-on-explicit-equals-for-boxed-null to the compiler.
Breaking
change:
fix
for
platform
null
escaping
through
an
inlined
extension
receiver
Inline extension functions that were called on a null value of a platform type did not check the receiver for null and would thus allow null to
escape into the other code. Kotlin 1.2 forces this check at the call sites, throwing an exception if the receiver is null.
To switch to the old behavior, pass the fallback flag -Xno-receiver-assertions to the compiler.
JavaScript
backend
TypedArrays
support
enabled
by
default
The JS typed arrays support that translates Kotlin primitive arrays, such as IntArray, DoubleArray, into JavaScript typed arrays, that was
previously an opt-in feature, has been enabled by default.
Tools
Warnings
as
errors
The compiler now provides an option to treat all warnings as errors. Use -Werror on the command line, or the following Gradle snippet:
compileKotlin {
kotlinOptions.allWarningsAsErrors = true
}
What's
new
in
Kotlin
1.1
Release date: 15 February 2016
Table
of
contents
Coroutines
Standard library
JVM backend
JavaScript backend
JavaScript
Starting with Kotlin 1.1, the JavaScript target is no longer considered experimental. All language features are supported, and there are
236
many new tools for integration with the frontend development environment. See below for a more detailed list of changes.
Coroutines
(experimental)
The key new feature in Kotlin 1.1 is coroutines, bringing the support of async/await, yield, and similar programming patterns. The key
feature of Kotlin's design is that the implementation of coroutine execution is part of the libraries, not the language, so you aren't bound to
any specific programming paradigm or concurrency library.
A coroutine is effectively a light-weight thread that can be suspended and resumed later. Coroutines are supported through suspending
functions: a call to such a function can potentially suspend a coroutine, and to start a new coroutine we usually use an anonymous
suspending functions (i.e. suspending lambdas).
Here, async { ... } starts a coroutine and, when we use await(), the execution of the coroutine is suspended while the operation being
awaited is executed, and is resumed (possibly on a different thread) when the operation being awaited completes.
The standard library uses coroutines to support lazily generated sequences with yield and yieldAll functions. In such a sequence, the block
of code that returns sequence elements is suspended after each element has been retrieved, and resumed when the next element is
requested. Here's an example:
import kotlin.coroutines.experimental.*
Run the code above to see the result. Feel free to edit it and run again!
For more information, please refer to the coroutines documentation and tutorial.
Note that coroutines are currently considered an experimental feature, meaning that the Kotlin team is not committing to supporting the
237
backwards compatibility of this feature after the final 1.1 release.
Other
language
features
Type
aliases
A type alias allows you to define an alternative name for an existing type. This is most useful for generic types such as collections, as well
as for function types. Here is an example:
//sampleStart
typealias OscarWinners = Map<String, String>
// Note that the type names (initial and the type alias) are interchangeable:
fun checkLaLaLandIsTheBestMovie(oscarWinners: Map<String, String>) =
oscarWinners["Best picture"] == "La La Land"
//sampleEnd
See the type aliases documentation and KEEP for more details.
Bound
callable
references
You can now use the :: operator to get a member reference pointing to a method or property of a specific object instance. Previously this
could only be expressed with a lambda. Here's an example:
//sampleStart
val numberRegex = "\\d+".toRegex()
val numbers = listOf("abc", "123", "456").filter(numberRegex::matches)
//sampleEnd
Sealed
and
data
classes
Kotlin 1.1 removes some of the restrictions on sealed and data classes that were present in Kotlin 1.0. Now you can define subclasses of a
238
top-level sealed class on the top level in the same file, and not just as nested classes of the sealed class. Data classes can now extend
other classes. This can be used to define a hierarchy of expression classes nicely and cleanly:
//sampleStart
sealed class Expr
Read the sealed classes documentation or KEEPs for sealed class and data class for more detail.
Destructuring
in
lambdas
You can now use the destructuring declaration syntax to unpack the arguments passed to a lambda. Here's an example:
Read the destructuring declarations documentation and KEEP for more details.
Underscores
for
unused
parameters
For a lambda with multiple parameters, you can use the _ character to replace the names of the parameters you don't use:
//sampleStart
map.forEach { _, value -> println("$value!") }
//sampleEnd
}
239
fun main(args: Array<String>) {
//sampleStart
val (_, status) = getResult()
//sampleEnd
println("status is '$status'")
}
Underscores
in
numeric
literals
Just as in Java 8, Kotlin now allows to use underscores in numeric literals to separate groups of digits:
//sampleStart
val oneMillion = 1_000_000
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010
//sampleEnd
Shorter
syntax
for
properties
For properties with the getter defined as an expression body, the property type can now be omitted:
//sampleStart
data class Person(val name: String, val age: Int) {
val isAdult get() = age >= 20 // Property type inferred to be 'Boolean'
}
//sampleEnd
fun main(args: Array<String>) {
val akari = Person("Akari", 26)
println("$akari.isAdult = ${akari.isAdult}")
}
Inline
property
accessors
You can now mark property accessors with the inline modifier if the properties don't have a backing field. Such accessors are compiled in
the same way as inline functions.
//sampleStart
public val <T> List<T>.lastIndex: Int
inline get() = this.size - 1
//sampleEnd
You can also mark the entire property as inline - then the modifier is applied to both accessors.
240
Read the inline functions documentation and KEEP for more details.
Local
delegated
properties
You can now use the delegated property syntax with local variables. One possible use is defining a lazily evaluated local variable:
import java.util.Random
Interception
of
delegated
property
binding
For delegated properties, it is now possible to intercept delegate to property binding using the provideDelegate operator. For example, if
we want to check the property name before binding, we can write something like this:
class MyUI {
val image by bindResource(ResourceID.image_id)
val text by bindResource(ResourceID.text_id)
}
The provideDelegate method will be called for each property during the creation of a MyUI instance, and it can p