Today, after a long chain of incremental 1.2.X updates, it’s time to see what’s coming in Kotlin 1.3. We are happy to announce the first preview version of the new major release: Kotlin 1.3-M1.
Kotlin 1.3 brings many advancements including graduation of coroutines, new experimental unsigned arithmetic, and much more. Please read on for the details.
We’d like to thank our external contributors whose pull requests and commits were included in this release: Raluca Sauciuc, Toshiaki Kameyama, Leonardo Lopes, Jake Wharton, Jeff Wright, Lucas Smaira, Mon_chi, Nico Mandery, Oskar Drozda.
The complete list of changes in this release can be found in the changelog.
Coroutines are graduating to stable
Finally, coroutines will not be experimental anymore in 1.3. Both the syntax and the Standard Library APIs are stabilized and will remain backwards-compatible in the future.
Coroutines have been improved significantly since their introduction in 1.1. Notable features include:
- KT-16908 Support callable references to suspending functions
- KT-18559 Serializability of all coroutine-related classes
The core APIs have been simplified and moved out of the
We are also working on a multiplatform version of the coroutine APIs, including iOS support through Kotlin/Native.
Migration to new coroutines
As we’ve said earlier, all the packages with coroutine-related functions in Kotlin have dropped
experimental from their package names, and
buildIterator functions have moved to their permanent place in the
On the language level, there is still a
suspend modifier to support coroutines, and all the rules for working with coroutines remain mostly the same as they were in the experimental version.
Continuation<T> interface is simplified. It has only one
resumeWith(result: SuccessOrFailure<T>) member function (for details see the
SuccessOrFailure section below). The
resume(value: T) and
resumeWithException(exception: Throwable) are now defined as extensions. This affects only a small minority of code that defines its own coroutine builders and leaves classic examples of wrapping callbacks into suspending functions mostly unchanged. For example, a definition of the suspending function
await() for the class
CompletableFuture<T> would still look like this:
Graduated coroutines use a different binary interface (the major difference being the change of package names) and are not binary-compatible with experimental coroutines. To ensure a smooth migration, we’ll add a compatibility layer in 1.3 and the classes for experimental coroutines will still remain in the standard library. The compiled Kotlin/JVM code that uses experimental coroutines from 1.1 or 1.2 would still continue to work in Kotlin 1.3.
However, the Kotlin 1.3-M1 release does not provide any support for invoking experimental suspending functions from code that is compiled with the language version 1.3. In order to try graduated coroutines in Kotlin 1.3-M1 with libraries that expose suspending functions in their APIs, you will need to use versions of these libraries that are compiled for Kotlin 1.3. This is a temporary inconvenience that we’ll fix soon.
We will be providing a version of
kotlinx.coroutines library with
x.x.x-eap13 version that is built with Kotlin 1.3 and drops
experimental from its package names for every
x.x.x version that we release while Kotlin 1.3 is in the preview phase.
The IDE will assist you in migrating to new coroutines. We’ll improve the range of supported migration scenarios before 1.3.
While the bigger new capabilities of 1.3 will be experimental (see below), we are releasing a number of smaller features for your convenience now.
when subject in a variable
The common case of capturing the subject expression of
when in a variable is now supported in the language:
This small addition makes the
response variable properly scoped within
when, and makes the logic flow in a more expression-like fashion.
This was one of the most popular feature requests in our issue tracker. Thanks to all voters for your feedback!
@JvmField in companions of interfaces
Your Kotlin interfaces can now expose static members (fields and methods) to Java clients. The syntax is similar to that for classes; a companion object of an interface can now have
@JvmField is an all-or-nothing annotation here: to use it on interface companion properties, all of them must be public final vals and all of them must be annotated.
To use the
@JvmStatic annotation on interface companion members, the
-jvm-target compiler option must be at least
Nested declarations in annotation classes
Before 1.3, annotation classes could not have bodies in Kotlin. This release relaxes this limitation, allowing them to have nested classes, interfaces, and objects including a companion object. So, for example, it becomes possible to nest one annotation into another:
@JvmStatic are supported in interfaces, it is now possible to declare such members in annotation companion objects:
Functional types of higher arity
A function type can now have more than 22 parameters! We have pushed that limit to 255 parameters, which is the practical maximum number of parameters a method can have on the JVM. To find out how we’ve managed to do that without introducing another 233 classes, see the corresponding KEEP.
Experimental language features
As coroutines have demonstrated, providing early access to bigger features through making them experimental helps us gather invaluable feedback from the community. We’ll keep using this technique to make sure that Kotlin gets only battle-tested design choices that will last.
Kotlin 1.3 brings three exciting new features that will remain experimental for now. An explicit opt-in is required in your project in order to use them. Without an opt-in, usages of a feature will be marked as warnings or errors.
Inline classes allow wrapping a value of some type without creating an actual wrapper object.
When such a class is used, the compiler inlines its content and operations are performed on the wrapped value itself. Hence, this
results in the same compiled code as this:
Inline classes are similar to type aliases, but they are not assignment-compatible with the underlying value type, so you cannot assign a
String to a variable of type
Name, and vice versa.
Since inline classes have no identity, the
=== operator cannot be used on them.
There are still places where inline classes result in wrappers being created, similar to how
Int can be primitive in some usages and boxed in others (“auto-boxing”):
This feature can be enabled with the compiler option
See this KEEP for details. Be sure to read the “Limitations” section.
Unsigned integer types
The most obvious application of inline classes is unsigned integer types. The Standard Library now has
UShort defined as inline classes wrapping the corresponding signed counterparts. They define their own arithmetic operations that interpret the storage value as an unsigned integer.
In addition to the new types, there are new language features to support them, which makes these types special.
- Varargs of unsigned types are allowed, unlike other inline classes
Unsigned number literals are provided to simplify initializing variables of unsigned types
Constant values of unsigned types are allowed
Note that 1.3-M1 does not yet allow complex const expressions of unsigned types:
Such expressions will be supported a bit later.
Unsigned types are provided as an experimental API: you need to opt in for them, otherwise a warning will be issued at the use site. To opt in:
- either annotate the code element that uses unsigned types with the
- or specify the
Additionally, if you are a library author and are going to use experimental unsigned types, we recommend that you annotate parts of your API with the
@ExperimentalUnsignedTypes annotation. This will propagate the experimentality of unsigned types to your library’s users.
More details about unsigned types can be found in this KEEP.
Annotations for marking an experimental API and opting-in for it
The mechanism of experimental unsigned types opt-in described above is also available in a generic way to library authors. It allows you to provide an experimental API (i.e. one that is subject to future changes), which may break at any moment and require any usages to be fixed and recompiled.
Users of experimental APIs may opt in by agreeing essentially to the following: “I understand that I’m using an experimental declaration that may break at any time”. Without such explicit consent from the user, a warning or error will be reported on usages of experimental APIs.
The ultimate goal is to allow library authors to release APIs earlier and more frequently without a commitment to backward compatibility (source or binary).
Experimental API annotations are described in detail in this KEEP.
New Standard Library APIs
Now let’s look at what new APIs are available in the standard library in this release.
The inline class
SuccessOrFailure is effectively a discriminated union between successful and failed outcomes of execution of a Kotlin function:
Success T | Failure Throwable.
It has been introduced to allow for capturing the result of a function execution, whether successful or not, in order to process it at a later time.
The primary driver for introducing this class is the new
Continuation interface, where we want to have a single
resumeWith(result: SuccessOrFailure<T>) function instead of two,
Note that the Kotlin style guide discourages using
SuccessOrFailure type as a return type of Kotlin functions. This is similar to how users are encouraged to have
suspend functions return some type instead of plain functions returning a
Deferred of that type.
There are a few exceptions from this rule, which are explained in more detail in the proposal KEEP-127. Scroll down to the section on style and exceptions.
Multiplatform random number generator
While there’s no problem with generating random numbers in Kotlin/JVM (aside from
ThreadLocalRandom being unavailable prior to JDK 7), no uniform API is yet available to do that in Kotlin for other platforms and, more importantly, in multiplatform code.
This release introduces a new common
Random abstract class, which serves as a base class for random number generator implementations.
Note that if you just need a random number, there’s no need to inherit and implement this class. The default random number generator implementation is always at hand: it is the
Random companion object. So getting a number is as easy as
A repeatable random generator initialized with a particular seed can be obtained with the top-level function
For details please refer to this KEEP-131.
Companion object for
Basic types in Kotlin such as
String have a companion with some properties like
Until recently, the
Boolean type stood aside having no companion object.
New constants in companion objects of basic types
Existing companion objects of basic types have received these new properties:
SIZE_BYTESconstants, telling how many bits or bytes a value of that type takes in binary form.
MAX_VALUEconstants equal to
isNullOrEmpty and orEmpty extensions
orEmpty extensions on nullable collection-like types are not new in the standard library. 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
This release improves the API’s consistency by providing an
orEmpty() extension for sequences and an
isNullOrEmpty extension for collections, maps, and arrays of objects.
Announcing breaking changes
Some bug fixes introduce changes that are formally breaking. To ensure smooth migration, we deprecate old behavior, report warnings and provide migration tools whenever possible, and always announce such changes in advance.
Note that this is merely an announcement, so some of the changes listed below are not implemented yet and will be implemented in the following milestones.
You can consult the changelog to find out which of these changes have made it into this release.
- KT-11567 Companion object instance field is no longer public when the companion object itself is not public
- KT-16615 Initialization of properties without
constmodifier is changed so Java does not treat them like constants
- KT-21354 An array is captured before the
for-loop where it is iterated, so its reassignment inside the loop does not affect the iteration
- KT-22275 The type of exceptions thrown from failed null checks is being unified to
- KT-19532 Evaluation order of constructor arguments regarding
<clinit>call is changed
Previously deprecated feature usages that are now prohibited:
- KT-16681 val reassignment in its getter
- KT-16310 Nested classes in enum entries
- KT-19618 Data classes overriding
copywith the generated method
- KT-17981 Inner classes inheriting
Throwablethat capture generic parameters from the outer class
- KT-21515 Accessible classes and interfaces nested in companion objects
- KT-25333 Java static members accessible through supertypes of companion object
- KT-23153 Non-constant vararg annotation parameters
- KT-23277 Local annotation classes
- KT-22517 Smart casts for local delegated properties
modoperator convention. Note that operator
remshould be used instead of
modsince Kotlin 1.1
- KT-20588, KT-20589 Passing single element to vararg in named form
- KT-13762 Annotations with target
EXPRESSIONcannot have retention other than
- KT-22379 Smart cast is removed after while loops with
- KT-20830 Propagation of Java types nullability enhanced by annotations
setparamannotation target for a parameter declaration
Standard library changes
- KT-21784 The
org.jetbrains.annotationspackage is being removed from the standard library in the compiler distribution. Note that the maven standard library artifacts are not affected.
Array.copyOfRangethrows an exception when indices are out of bounds instead of enlarging the returned array
- KT-17176 Progressions of ints and longs with a step of
Long.MIN_VALUEare outlawed and won’t be allowed to be instantiated
- KT-16097 Check for index overflow in operations on very long sequences
- KT-21049 Unify split by an empty match regex result across the platforms
Note that the backward compatibility guarantees do not cover pre-release versions: the features and API can change in subsequent releases. When we reach a final RC, all binaries produced by pre-release versions will be outlawed by the compiler, and you will be required to recompile everything that was compiled by 1.3‑Mx.
However, all the code compiled by 1.2.x and earlier releases will be perfectly fine then without recompilation.
How to Try It
In Maven/Gradle: Add
http://dl.bintray.com/kotlin/kotlin-eap as a repository for the build script and your projects; use
1.3-M1 as the version number for the compiler plugin and the standard library.
In IntelliJ IDEA: Go to Tools → Kotlin → Configure Kotlin Plugin Updates, then select “Early Access Preview 1.3” in the Update channel drop-down list, and then click Check for updates.
The command-line compiler can be downloaded from the Github release page.
On try.kotlinlang.org: Use the drop-down list in the bottom right-hand corner to change the compiler version to 1.3‑M1.