What's new in Kotlin 1.5.30
Kotlin 1.5.30 offers language updates including previews of future changes, various improvements in platform support and tooling, and new standard library functions.
Here are some major improvements:
Language features, including experimental sealed
when
statements, changes in using opt-in requirement, and othersNative support for Apple silicon
Kotlin/JS IR backend reaches Beta
Improved Gradle plugin experience
You can also find a short overview of the changes in the release blog post and this video:
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
An exhaustive when
statement contains branches for either all possible types or values of its subject, or for certain types and includes an else
branch to cover any remaining 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.
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.
Suspending functions as supertypes
Kotlin 1.5.30 provides a preview of the ability to use a suspend
functional type as a supertype with some limitations.
Use the -language-version 1.6
compiler option to enable the feature:
The feature has the following restrictions:
You can't mix an ordinary functional type and a
suspend
functional type as supertype. This is because of the implementation details ofsuspend
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 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.
Learn more about opt-in requirements.
Changes to using opt-in requirement annotations with different targets
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 override is allowed only if its basic declaration is also marked.
Marking backing fields and getters is forbidden. You can mark the basic property instead.
Setting
TYPE
andTYPE_PARAMETER
annotation targets is forbidden at the opt-in requirement annotation declaration site.
Learn more about opt-in requirements.
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.
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:
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
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.
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.
Learn more about instantiation of annotation classes in this KEEP
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:
ignore
to ignore nullability mismatcheswarn
to report warningsstrict
to report errors.
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-annotations=@io.reactivex.rxjava3.annotations:strict
. Note that all such nullability mismatches are warnings by default.
Kotlin/Native
Kotlin/Native has received various changes and improvements:
Improved Swift/Objective-C mapping for objects and companion objects
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.
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. We will keep working to improve the user experience with the new targets.
Improved Kotlin DSL for the CocoaPods Gradle plugin
New parameters for Kotlin/Native frameworks
Kotlin 1.5.30 introduces the improved CocoaPods Gradle plugin DSL for Kotlin/Native frameworks. In addition to the name of the framework, you can specify other parameters in the Pod configuration:
Specify the dynamic or static version of the framework
Enable export dependencies explicitly
Enable Bitcode embedding
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:
Support custom names for Xcode configuration
The Kotlin CocoaPods Gradle plugin supports custom names in the Xcode build configuration. It will also help you if you're using special names for the build configuration in Xcode, for example Staging
.
To specify a custom name, use the xcodeConfigurationToNativeBuildType
parameter in the cocoapods
section of your build.gradle(.kts)
file:
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.
Experimental interoperability with Swift 5.5 async/await
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:
To access them in Swift, you can use the shared
and companion
properties:
Learn more about Swift/Objective-C interoperability.
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
:
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.
To use XCFrameworks, update your build.gradle(.kts)
script:
When you declare XCFrameworks, these new Gradle tasks will be registered:
assembleXCFramework
assembleDebugXCFramework
(additionally debug artifact that contains dSYMs)assembleReleaseXCFramework
Learn more about XCFrameworks in this WWDC video.
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.
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.
Learn how to debug Kotlin/JS in the browser or IntelliJ IDEA Ultimate.
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 versionsAn easier way to explicitly specify the Kotlin daemon's JVM arguments
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.
Compile and test code with an unreleased language version.
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.
The Kotlin Gradle plugin supports Java toolchains for Kotlin/JVM compilation tasks. A Java toolchain:
Sets the
jdkHome
option available for JVM targets.Sets the
kotlinOptions.jvmTarget
to the toolchain's JDK version if the user didn't set thejvmTarget
option explicitly. If the toolchain is not configured, thejvmTarget
field uses the default value. Learn more about JVM target compatibility.Affects which JDK
kapt
workers are running on.
Use the following code to set a toolchain. Replace the placeholder <MAJOR_JDK_VERSION>
with the JDK version you would like to use:
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:
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:
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=500mIf 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=500mYou can add the
kotlin.daemon.jvmargs
property in thegradle.properties
file:kotlin.daemon.jvmargs=-Xmx1500m -Xms=500mYou can specify arguments in the
kotlin
extension:kotlin { kotlinDaemonJvmArgs = listOf("-Xmx486m", "-Xms256m", "-XX:+UseParallelGC") }kotlin { kotlinDaemonJvmArgs = ["-Xmx486m", "-Xms256m", "-XX:+UseParallelGC"] }You can specify arguments for a specific task:
tasks .matching { it.name == "compileKotlin" && it is CompileUsingKotlinDaemon } .configureEach { (this as CompileUsingKotlinDaemon).kotlinDaemonJvmArguments.set(listOf("-Xmx486m", "-Xms256m", "-XX:+UseParallelGC")) }tasks .matching { it.name == "compileKotlin" && it instanceof CompileUsingKotlinDaemon } .configureEach { kotlinDaemonJvmArguments.set(["-Xmx1g", "-Xms512m"]) }
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
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 components, each in its own unit. Each component is a number followed by the unit's abbreviated name: d
, h
, m
, s
. For example:
Example of function call | Previous output | Current output |
---|---|---|
Duration.days(45).toString() |
|
|
Duration.days(1.5).toString() |
|
|
Duration.minutes(1230).toString() |
|
|
Duration.minutes(2415).toString() |
|
|
Duration.minutes(920).toString() |
|
|
Duration.seconds(1.546).toString() |
|
|
Duration.milliseconds(25.12).toString() |
|
|
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.
Parsing Duration from String
In Kotlin 1.5.30, there are new functions in the Duration API:
parse()
, which supports parsing the outputs of:parseIsoString()
, which only parses from the format produced bytoIsoString()
.parseOrNull()
andparseIsoStringOrNull()
, which behave like the functions above but returnnull
instead of throwingIllegalArgumentException
on invalid duration formats.
Here are some examples of parse()
and parseOrNull()
usages:
And here are some examples of parseIsoString()
and parseIsoStringOrNull()
usages:
Matching with Regex at a particular position
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
.
matchesAt()
returns a boolean result:
matchAt()
returns the match if one is found or null
if one isn't:
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.
A similar function was also added to CharSequence
:
Serialization 1.3.0-RC
kotlinx.serialization
1.3.0-RC is here with new JSON serialization capabilities:
Java IO streams serialization
Property-level control over default values
An option to exclude null values from serialization
Custom class discriminators in polymorphic serialization
Learn more in the changelog.