Kotlin
A concise multiplatform language developed by JetBrains
See what’s coming in Kotlin 1.3-M1
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 experimental
packages.
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 buildSequence
and buildIterator
functions have moved to their permanent place in the kotlin.sequences
package.
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.
The graduated 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.
New features
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.
Capturing 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!
@JvmStatic
and @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 @JvmStatic
or @JvmField
inside:
Note that @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 1.8
.
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:
Since @JvmField
and @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
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 -XXLanguage:+InlineClasses
.
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 UInt
, ULong
, UByte
, and 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
@UseExperimental(ExperimentalUnsignedTypes::class)
annotation - or specify the
-Xuse-experimental=kotlin.ExperimentalUnsignedTypes
compiler option.
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.
SuccessOrFailure
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, resume(T)
and resumeWithException(Throwable)
.
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 Random(seed)
For details please refer to this KEEP-131.
Companion object for Boolean
type
Basic types in Kotlin such as Int
, Char
, and String
have a companion with some properties like MIN_VALUE
.
Until recently, the Boolean
type stood aside having no companion object.
Our community members have convinced us that there are use cases for having a Boolean
companion even without any properties, and Leonardo Lopes has helped implement it.
New constants in companion objects of basic types
Existing companion objects of basic types have received these new properties:
Byte
,Short
,Int
,Long
,Char
now haveSIZE_BITS
andSIZE_BYTES
constants, telling how many bits or bytes a value of that type takes in binary form.-
Char
now hasMIN_VALUE
andMAX_VALUE
constants equal to'\u0000'
and'\uFFFF'
, respectively.
isNullOrEmpty and orEmpty extensions
isNullOrEmpty
and 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 null
.
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.
Compiler changes
- KT-11567 Companion object instance field is no longer public when the companion object itself is not public
- KT-16615 Initialization of properties without
const
modifier 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
NullPointerException
- 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
copy
with the generated method - KT-17981 Inner classes inheriting
Throwable
that 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
- KT-24197
mod
operator convention. Note that operatorrem
should be used instead ofmod
since Kotlin 1.1 - KT-20588, KT-20589 Passing single element to vararg in named form
- KT-13762 Annotations with target
EXPRESSION
cannot have retention other thanSOURCE
- KT-22379 Smart cast is removed after while loops with
break
- KT-20830 Propagation of Java types nullability enhanced by annotations
- KT-9580
setparam
annotation target for a parameter declaration
Standard library changes
- KT-21784 The
org.jetbrains.annotations
package is being removed from the standard library in the compiler distribution. Note that the maven standard library artifacts are not affected. - KT-19489
Array.copyOfRange
throws 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
Int.MIN_VALUE
andLong.MIN_VALUE
are 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
Pre-release notes
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.