Kotlin
A concise multiplatform language developed by JetBrains
A major release just around the corner — meet Kotlin 1.3-M2
Moving full steam towards Kotlin 1.3, we’re happy to announce the second milestone release, Kotlin 1.3-M2, which unveils new features and improves the stability of those already announced. Some highlights:
- Contracts improve smart-casts and other compile-time analyses
- New Standard Library functions for unsigned types and collections
- Reflection for coroutines
- A migration layer to aid migration onto new coroutines being graduated in 1.3
- Numerous bugfixes related to inline classes
We’d like to thank our external contributors whose commits were included in this release: Leonardo Colman Lopes and Pap Lőrinc.
The complete list of changes in this release can be found in the changelog.
We appreciate your feedback regarding the new features or any problems that you may run into with this release.
Contracts
In 1.3-M2 we introduce contracts, a new experimental addition to the Kotlin type system. Let’s consider a motivating example:
Here, require()
is a function defined in the Standard Library that throws an exception when its argument is false (similar to assert()
, but doesn’t depend on the -ea
flag). Thus, if the println()
gets executed, then x
has to be a String, and a smart cast would be very logical in this line. The problem is: the compiler normally only looks at function signatures, so it knows nothing about how require()
is implemented, and thus can’t infer that x
is now certainly an instance of String.
With contracts, a function can tell the compiler things like “I affect smart casts this way” or “I execute this lambda immediately and exactly once”. Contracts enrich the type information available through the function signature (“I take a nullable list of T and return a Boolean”) with additional meanings useful at the call site, e.g. “I only return false for non-null lists”.
Kotlin standard library already comes with contracts added to several functions. They work regardless of the experimental flags.
Currently, the Kotlin compiler uses contracts for two types of improvements:
- Making smart casts even smarter:
Applies for functions:
check
,checkNotNull
,require
,requireNotNull
,kotlin.test.assertTrue
,kotlin.test.assertFalse
,kotlin.test.assertNotNull
,isNullOrEmpty
,isNullOrBlank
- Analyzing variable initialization more accurately:
Applies for functions:
run
,let
,with
,apply
,also
,takeIf
,takeUnless
,synchronized
While the contracts of the standard functions listed above are stable, the declaration site syntax and APIs for defining contracts may be changed in the future. To specify contracts for your own functions, you have to opt into the experimental mode by using the @ExperimentalContracts
annotation:
Note that the contracts are not yet verified at the declaration site, so it’s your responsibility to provide accurate information there. See this KEEP for the syntax, as well as for compatibility guarantees and general design overview.
Coroutines update
Kotlin 1.3 graduates coroutines to stable changing several things in the APIs and ABIs based on the feedback we gathered during the experimental period. In the previous milestone, 1.3-M1, there was no migration support bridging the old experimental coroutines with new stable ones. Now, in 1.3-M2 we provide such support: you can simply call old suspend functions.
Also, Kotlin reflection now supports introspection for suspend
functions:
KCallable.isSuspend
KCallable.callSuspend
KCallable.callSuspendBy
The latter two allow for calling suspend
functions via reflection, so they are themselves marked suspend
.
Standard Library
Unsigned types
The library support has been improved for the unsigned integer types. Let’s walk through what has been introduced to make the unsigned types and arrays of unsigned types feel more like first-class citizens:
- Functions for converting unsigned integers to and from strings in an arbitrary base:
UInt.toString(base)
,String.toUInt(base)
etc.
- Extension functions
until
,downTo
,step
andreversed
to support more ways of creating ranges and progressions of unsigned integers.
- The arrays of unsigned integers do not implement the structural equality contract of
List
, same as the arrays of signed integers. To make it easy comparing these arrays or showing their contents as string thecontentEquals(other)
,contentHashCode()
,contentToString()
functions were introduced.
- Secondary constructors of unsigned arrays to create a zero-initialized array of unsigned integers of a given size.
- Extension functions to copy unsigned integer arrays and their subranges:
copyOf()
,copyOf(newSize)
,copyOfRange(fromIndex, toIndex)
.
- Extensions for reinterpreting an array of unsigned integers as an array of signed ones, and vice versa:
ByteArray.as/toUByteArray()
,UByteArray.as/toByteArray()
etc.
- Extensions for converting a specialized array of unsigned integers to an object array:
UIntArray.toTypedArray()
which returns anArray<UInt>
, etc
Copying 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.
associateWith
It is quite common situation when you have a list of keys and you 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) }
ifEmpty and ifBlank functions
Collections, maps, object arrays, char sequences and sequences now have ifEmpty
function, which allows to specify a substitute value that will be used instead of the receiver if it is empty.
Char sequences and strings in addition have ifBlank
extension that does the same thing as ifEmpty
, but checks for the string being all whitespace instead of empty.
Random API improvements
The Random
class, introduced in the previous 1.3-M1 release, has received extensions for generating unsigned numbers and arrays of unsigned bytes, thanks to our contributor Leonardo Colman Lopes: these are nextUInt
, nextULong
and nextUBytes
extensions:
Also we’re introducing a helpful extension for collections, arrays and even ranges to get a random element from among all of the elements of that collection/array/range. It’s called just random()
:
Sealed classes reflection
We’ve added a new API to kotlin-reflect
that can be used to enumerate all direct subtypes of a sealed
class, namely KClass.sealedSubclasses
.
Inline classes
In 1.3-M2 we introduce automatic mangling for names of functions that use inline classes in their signatures. We do it to prevent platform signature clashes when there are several overloads which are different only in the inline type, but not in the carrier type:
Another reason for mangling is to forbid (accidental) usage from Java, which may be undesired as inline classes are a purely Kotlin concept.
Mangled names will have the form of foo-<some string based on the signature>
Another two improvements for inline classes in this release are:
- the support for secondary constructors
- automatically generated
toString
/equals
/hashCode
functions
Language changes
We’re deprecating the support for older source language versions through the -language-version
flag with values 1.0
and 1.1
for kotlinc-1.3 and above. Note that this change only affects compilation of source code for old target versions; all binaries ever compiled with stable language versions will be supported by later versions of kotlinc. To compile your sources with Kotlin 1.0 and 1.1 you can use the corresponding old versions of kotlinc.
Also, certain new restrictions were added in this update aimed to ensure stable and well-defined behavior regarding some error-prone constructs:
- Misleading labels on statements other than loops, inline lambdas, and inline anonymous functions, such as
foo@ val bar = 1
, had no real meaning or use case and are now prohibited (KT-22274) - Getter-targeted annotations on annotation constructor parameters, which were not represented in the binaries and thus never worked, are now written to the annotation class getter methods (KT-25287)
- Unresolved reference errors that were missing in data class constructor’s
@get:
annotations are now properly reported (KT-19628)
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-M2
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‑M2.
Let’s Kotlin!