What's new in Kotlin 1.8.0
The Kotlin 1.8.0 release is out and here are some of its biggest highlights:
New experimental functions for JVM: recursively copy or delete directory content
kotlin-stdlib-jdk7
andkotlin-stdlib-jdk8
merged intokotlin-stdlib
IDE support
The Kotlin plugin that supports 1.8.0 is available for:
IDE | Supported versions |
---|---|
IntelliJ IDEA | 2021.3, 2022.1, 2022.2 |
Android Studio | Electric Eel (221), Flamingo (222) |
Kotlin/JVM
Starting with version 1.8.0, the compiler can generate classes with a bytecode version corresponding to JVM 19. The new language version also includes:
Ability to not generate TYPE_USE and TYPE_PARAMETER annotation targets
If a Kotlin annotation has TYPE
among its Kotlin targets, the annotation maps to java.lang.annotation.ElementType.TYPE_USE
in its list of Java annotation targets. This is just like how the TYPE_PARAMETER
Kotlin target maps to the java.lang.annotation.ElementType.TYPE_PARAMETER
Java target. This is an issue for Android clients with API levels less than 26, which don't have these targets in the API.
Starting with Kotlin 1.8.0, you can use the new compiler option -Xno-new-java-annotation-targets
to avoid generating the TYPE_USE
and TYPE_PARAMETER
annotation targets.
A new compiler option for disabling optimizations
Kotlin 1.8.0 adds a new -Xdebug
compiler option, which disables optimizations for a better debugging experience. For now, the option disables the "was optimized out" feature for coroutines. In the future, after we add more optimizations, this option will disable them, too.
The "was optimized out" feature optimizes variables when you use suspend functions. However, it is difficult to debug code with optimized variables because you don't see their values.
Removal of the old backend
In Kotlin 1.5.0, we announced that the IR-based backend became Stable. That meant that the old backend from Kotlin 1.4.* was deprecated. In Kotlin 1.8.0, we've removed the old backend completely. By extension, we've removed the compiler option -Xuse-old-backend
and the Gradle useOldBackend
option.
Support for Lombok's @Builder annotation
The community has added so many votes for the Kotlin Lombok: Support generated builders (@Builder) YouTrack issue that we just had to support the @Builder annotation.
We don't yet have plans to support the @SuperBuilder
or @Tolerate
annotations, but we'll reconsider if enough people vote for the @SuperBuilder and @Tolerate issues.
Kotlin/Native
Kotlin 1.8.0 includes changes to Objective-C and Swift interoperability, support for Xcode 14.1, and improvements to the CocoaPods Gradle plugin:
Support for Xcode 14.1
The Kotlin/Native compiler now supports the latest stable Xcode version, 14.1. The compatibility improvements include the following changes:
There's a new
watchosDeviceArm64
preset for the watchOS target that supports Apple watchOS on ARM64 platforms.The Kotlin CocoaPods Gradle plugin no longer has bitcode embedding for Apple frameworks by default.
Platform libraries were updated to reflect the changes to Objective-C frameworks for Apple targets.
Improved Objective-C/Swift interoperability
To make Kotlin more interoperable with Objective-C and Swift, three new annotations were added:
@ObjCName
allows you to specify a more idiomatic name in Swift or Objective-C, instead of renaming the Kotlin declaration.The annotation instructs the Kotlin compiler to use a custom Objective-C and Swift name for this class, property, parameter, or function:
@ObjCName(swiftName = "MySwiftArray") class MyKotlinArray { @ObjCName("index") fun indexOf(@ObjCName("of") element: String): Int = TODO() } // Usage with the ObjCName annotations let array = MySwiftArray() let index = array.index(of: "element")@HiddenFromObjC
allows you to hide a Kotlin declaration from Objective-C.The annotation instructs the Kotlin compiler not to export a function or property to Objective-C and, consequently, Swift. This can make your Kotlin code more Objective-C/Swift-friendly.
@ShouldRefineInSwift
is useful for replacing a Kotlin declaration with a wrapper written in Swift.The annotation instructs the Kotlin compiler to mark a function or property as
swift_private
in the generated Objective-C API. Such declarations get the__
prefix, which makes them invisible to Swift code.You can still use these declarations in your Swift code to create a Swift-friendly API, but they won't be suggested by Xcode's autocompletion, for example.
For more information on refining Objective-C declarations in Swift, see the official Apple documentation.
The Kotlin team is very grateful to Rick Clephas for implementing these annotations.
Dynamic frameworks by default in the CocoaPods Gradle plugin
Starting with Kotlin 1.8.0, Kotlin frameworks registered by the CocoaPods Gradle plugin are linked dynamically by default. The previous static implementation was inconsistent with the behavior of the Kotlin Gradle plugin.
If you have an existing project with a static linking type and you upgrade to Kotlin 1.8.0 (or change the linking type explicitly), you may encounter an error with the project's execution. To fix it, close your Xcode project and run pod install
in the Podfile directory.
For more information, see the CocoaPods Gradle plugin DSL reference.
Kotlin Multiplatform: A new Android source set layout
Kotlin 1.8.0 introduces a new Android source set layout that replaces the previous naming schema for directories, which is confusing in multiple ways.
Consider an example of two androidTest
directories created in the current layout. One is for KotlinSourceSets
and the other is for AndroidSourceSets
:
They have different semantics: Kotlin's
androidTest
belongs to theunitTest
type, whereas Android's belongs to theintegrationTest
type.They create a confusing
SourceDirectories
layout, assrc/androidTest/kotlin
has aUnitTest
andsrc/androidTest/java
has anInstrumentedTest
.Both
KotlinSourceSets
andAndroidSourceSets
use a similar naming schema for Gradle configurations, so the resulting configurations ofandroidTest
for both Kotlin's and Android's source sets are the same:androidTestImplementation
,androidTestApi
,androidTestRuntimeOnly
, andandroidTestCompileOnly
.
To address these and other existing issues, we've introduced a new Android source set layout. Here are some of the key differences between the two layouts:
KotlinSourceSet naming schema
Current source set layout | New source set layout |
---|---|
|
|
{AndroidSourceSet.name}
maps to {KotlinSourceSet.name}
as follows:
Current source set layout | New source set layout | |
---|---|---|
main | androidMain | androidMain |
test | androidTest | androidUnitTest |
androidTest | androidAndroidTest | androidInstrumentedTest |
SourceDirectories
Current source set layout | New source set layout |
---|---|
The layout adds additional |
|
{AndroidSourceSet.name}
maps to {SourceDirectories included}
as follows:
Current source set layout | New source set layout | |
---|---|---|
main | src/androidMain/kotlin, src/main/kotlin, src/main/java | src/androidMain/kotlin, src/main/kotlin, src/main/java |
test | src/androidTest/kotlin, src/test/kotlin, src/test/java | src/androidUnitTest/kotlin, src/test/kotlin, src/test/java |
androidTest | src/androidAndroidTest/kotlin, src/androidTest/java | src/androidInstrumentedTest/kotlin, src/androidTest/java, src/androidTest/kotlin |
The location of the AndroidManifest.xml file
Current source set layout | New source set layout |
---|---|
src/{AndroidSourceSet.name}/AndroidManifest.xml | src/{KotlinSourceSet.name}/AndroidManifest.xml |
{AndroidSourceSet.name}
maps to{AndroidManifest.xml location}
as follows:
Current source set layout | New source set layout | |
---|---|---|
main | src/main/AndroidManifest.xml | src/androidMain/AndroidManifest.xml |
debug | src/debug/AndroidManifest.xml | src/androidDebug/AndroidManifest.xml |
The relation between Android and common tests
The new Android source set layout changes the relation between Android-instrumented tests (renamed to androidInstrumentedTest
in the new layout) and common tests.
Previously, there was a default dependsOn
relation between androidAndroidTest
and commonTest
. In practice, it meant the following:
The code in
commonTest
was available inandroidAndroidTest
.expect
declarations incommonTest
had to have correspondingactual
implementations inandroidAndroidTest
.Tests declared in
commonTest
were also running as Android instrumented tests.
In the new Android source set layout, the dependsOn
relation is not added by default. If you prefer the previous behavior, manually declare this relation in your build.gradle.kts
file:
Support for Android flavors
Previously, the Kotlin Gradle plugin eagerly created source sets that correspond to Android source sets with debug
and release
build types or custom flavors like demo
and full
. It made them accessible by constructions like val androidDebug by getting { ... }
.
In the new Android source set layout, those source sets are created in the afterEvaluate
phase. It makes such expressions invalid, leading to errors like org.gradle.api.UnknownDomainObjectException: KotlinSourceSet with name 'androidDebug' not found
.
To work around that, use the new invokeWhenCreated()
API in your build.gradle.kts
file:
Configuration and setup
The new layout will become the default in future releases. You can enable it now with the following Gradle option:
The usage of the previous Android-style directories is now discouraged. Kotlin 1.8.0 marks the start of the deprecation cycle, introducing a warning for the current layout. You can suppress the warning with the following Gradle property:
Kotlin/JS
Kotlin 1.8.0 stabilizes the JS IR compiler backend and brings new features to JavaScript-related Gradle build scripts:
Stable JS IR compiler backend
Starting with this release, the Kotlin/JS intermediate representation (IR-based) compiler backend is Stable. It took a while to unify infrastructure for all three backends, but they now work with the same IR for Kotlin code.
As a consequence of the stable JS IR compiler backend, the old one is deprecated from now on.
Incremental compilation is enabled by default along with the stable JS IR compiler.
If you still use the old compiler, switch your project to the new backend with the help of our migration guide.
New settings for reporting that yarn.lock has been updated
If you use the yarn
package manager, there are three new special Gradle settings that could notify you if the yarn.lock
file has been updated. You can use these settings when you want to be notified if yarn.lock
has been changed silently during the CI build process.
These three new Gradle properties are:
YarnLockMismatchReport
, which specifies how changes to theyarn.lock
file are reported. You can use one of the following values:FAIL
fails the corresponding Gradle task. This is the default.WARNING
writes the information about changes in the warning log.NONE
disables reporting.
reportNewYarnLock
, which reports about the recently createdyarn.lock
file explicitly. By default, this option is disabled: it's a common practice to generate a newyarn.lock
file at the first start. You can use this option to ensure that the file has been committed to your repository.yarnLockAutoReplace
, which replacesyarn.lock
automatically every time the Gradle task is run.
To use these options, update your build script file build.gradle.kts
as follows:
Add test targets for browsers via Gradle properties
Starting with Kotlin 1.8.0, you can set test targets for different browsers right in the Gradle properties file. Doing so shrinks the size of the build script file as you no longer need to write all targets in build.gradle.kts
.
You can use this property to define a list of browsers for all modules, and then add specific browsers in the build scripts of particular modules.
For example, the following line in your Gradle property file will run the test in Firefox and Safari for all modules:
See the full list of available values for the property on GitHub.
The Kotlin team is very grateful to Martynas Petuška for implementing this feature.
New approach to adding CSS support to your project
This release provides a new approach to adding CSS support to your project. We assume that this will affect a lot of projects, so don't forget to update your Gradle build script files as described below.
Before Kotlin 1.8.0, the cssSupport.enabled
property was used to add CSS support:
Now you should use the enabled.set()
method in the cssSupport {}
block:
Gradle
Kotlin 1.8.0 fully supports Gradle versions 7.2 and 7.3. You can also use Gradle versions up to the latest Gradle release, but if you do, keep in mind that you might encounter deprecation warnings or some new Gradle features might not work.
This version brings lots of changes:
Usage of the latest kotlin-stdlib version in transitive dependencies
Obligatory check for JVM target compatibility equality of related Kotlin and Java compile tasks
Resolution of Kotlin Gradle plugins' transitive dependencies
Exposing Kotlin compiler options as Gradle lazy properties
To expose available Kotlin compiler options as Gradle lazy properties and to integrate them better into the Kotlin tasks, we made lots of changes:
Compile tasks have the new
compilerOptions
input, which is similar to the existingkotlinOptions
but usesProperty
from the Gradle Properties API as the return type:tasks.named("compileKotlin", org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile::class.java) { compilerOptions { useK2.set(true) } }The Kotlin tools tasks
KotlinJsDce
andKotlinNativeLink
have the newtoolOptions
input, which is similar to the existingkotlinOptions
input.New inputs have the
@Nested
Gradle annotation. Every property inside the inputs has a related Gradle annotation, such as@Input
or@Internal
.The Kotlin Gradle plugin API artifact has two new interfaces:
org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
, which has thecompilerOptions
input and thecompileOptions()
method. All Kotlin compilation tasks implement this interface.org.jetbrains.kotlin.gradle.tasks.KotlinToolTask
, which has thetoolOptions
input and thetoolOptions()
method. All Kotlin tool tasks –KotlinJsDce
,KotlinNativeLink
, andKotlinNativeLinkArtifactTask
– implement this interface.
Some
compilerOptions
use the new types instead of theString
type:KotlinVersion
(for theapiVersion
and thelanguageVersion
inputs)
For example, you can use
compilerOptions.jvmTarget.set(JvmTarget.JVM_11)
instead ofkotlinOptions.jvmTarget = "11"
.The
kotlinOptions
types didn't change, and they are internally converted tocompilerOptions
types.The Kotlin Gradle plugin API is binary-compatible with previous releases. There are, however, some source and ABI-breaking changes in the
kotlin-gradle-plugin
artifact. Most of these changes involve additional generic parameters to some internal types. One important change is that theKotlinNativeLink
task no longer inherits theAbstractKotlinNativeCompile
task.KotlinJsCompilerOptions.outputFile
and the relatedKotlinJsOptions.outputFile
options are deprecated. Use theKotlin2JsCompile.outputFileProperty
task input instead.
Limitations
Calling any setter or getter on kotlinOptions
delegates to the related property in the compilerOptions
. This introduces the following limitations:
compilerOptions
andkotlinOptions
cannot be changed in the task execution phase (see one exception in the paragraph below).freeCompilerArgs
returns an immutableList<String>
, which means that, for example,kotlinOptions.freeCompilerArgs.remove("something")
will fail.
Several plugins, including kotlin-dsl
and the Android Gradle plugin (AGP) with Jetpack Compose enabled, try to modify the freeCompilerArgs
attribute in the task execution phase. We've added a workaround for them in Kotlin 1.8.0. This workaround allows any build script or plugin to modify kotlinOptions.freeCompilerArgs
in the execution phase but produces a warning in the build log. To disable this warning, use the new Gradle property kotlin.options.suppressFreeCompilerArgsModificationWarning=true
. Gradle is going to add fixes for the kotlin-dsl
plugin and AGP with Jetpack Compose enabled.
Bumping the minimum supported versions
Starting with Kotlin 1.8.0, the minimum supported Gradle version is 6.8.3 and the minimum supported Android Gradle plugin version is 4.1.3.
See the Kotlin Gradle plugin compatibility with available Gradle versions in our documentation
Ability to disable the Kotlin daemon fallback strategy
There is a new Gradle property kotlin.daemon.useFallbackStrategy
, whose default value is true
. When the value is false
, builds fail on problems with the daemon's startup or communication. There is also a new useDaemonFallbackStrategy
property in Kotlin compile tasks, which takes priority over the Gradle property if you use both. If there is insufficient memory to run the compilation, you can see a message about it in the logs.
The Kotlin compiler's fallback strategy is to run a compilation outside the Kotlin daemon if the daemon somehow fails. If the Gradle daemon is on, the compiler uses the "In process" strategy. If the Gradle daemon is off, the compiler uses the "Out of process" strategy. Learn more about these execution strategies in the documentation. Note that silent fallback to another strategy can consume a lot of system resources or lead to non-deterministic builds; see this YouTrack issue for more details.
Usage of the latest kotlin-stdlib version in transitive dependencies
If you explicitly write Kotlin version 1.8.0 or higher in your dependencies, for example: implementation("org.jetbrains.kotlin:kotlin-stdlib:1.8.0")
, then the Kotlin Gradle Plugin will use that Kotlin version for transitive kotlin-stdlib-jdk7
and kotlin-stdlib-jdk8
dependencies. This is done to avoid class duplication from different stdlib versions (learn more about merging kotlin-stdlib-jdk7
and kotlin-stdlib-jdk8
into kotlin-stdlib
). You can disable this behavior with the kotlin.stdlib.jdk.variants.version.alignment
Gradle property:
If you run into issues with version alignment, align all versions via the Kotlin BOM by declaring a platform dependency on kotlin-bom
in your build script:
Learn about other cases and our suggested solutions in the documentation.
Obligatory check for JVM targets of related Kotlin and Java compile tasks
Starting from this release, the default value for the kotlin.jvm.target.validation.mode
property is error
for projects on Gradle 8.0+ (this version of Gradle has not been released yet), and the plugin will fail the build in the event of JVM target incompatibility.
The shift of the default value from warning
to error
is a preparation step for a smooth migration to Gradle 8.0. We encourage you to set this property to error
and configure a toolchain or align JVM versions manually.
Learn more about what can go wrong if you don't check the targets' compatibility.
Resolution of Kotlin Gradle plugins' transitive dependencies
In Kotlin 1.7.0, we introduced support for Gradle plugin variants. Because of these plugin variants, a build classpath can have different versions of the Kotlin Gradle plugins that depend on different versions of some dependency, usually kotlin-gradle-plugin-api
. This can lead to a resolution problem, and we would like to propose the following workaround, using the kotlin-dsl
plugin as an example.
The kotlin-dsl
plugin in Gradle 7.6 depends on the org.jetbrains.kotlin.plugin.sam.with.receiver:1.7.10
plugin, which depends on kotlin-gradle-plugin-api:1.7.10
. If you add the org.jetbrains.kotlin.gradle.jvm:1.8.0
plugin, this kotlin-gradle-plugin-api:1.7.10
transitive dependency may lead to a dependency resolution error because of a mismatch between the versions (1.8.0
and 1.7.10
) and the variant attributes' org.gradle.plugin.api-version
values. As a workaround, add this constraint to align the versions. This workaround may be needed until we implement the Kotlin Gradle Plugin libraries alignment platform, which is in the plans:
This constraint forces the org.jetbrains.kotlin:kotlin-sam-with-receiver:1.8.0
version to be used in the build classpath for transitive dependencies. Learn more about one similar case in the Gradle issue tracker.
Deprecations and removals
In Kotlin 1.8.0, the deprecation cycle continues for the following properties and methods:
In the notes for Kotlin 1.7.0 that the
KotlinCompile
task still had the deprecated Kotlin propertyclasspath
, which would be removed in future releases. Now, we've changed the deprecation level toerror
for theKotlinCompile
task'sclasspath
property. All compile tasks use thelibraries
input for a list of libraries required for compilation.We removed the
kapt.use.worker.api
property that allowed running kapt via the Gradle Workers API. By default, kapt has been using Gradle workers since Kotlin 1.3.70, and we recommend sticking to this method.In Kotlin 1.7.0, we announced the start of a deprecation cycle for the
kotlin.compiler.execution.strategy
property. In this release, we removed this property. Learn how to define a Kotlin compiler execution strategy in other ways.
Standard library
Kotlin 1.8.0:
Updates JVM compilation target.
Stabilizes a number of functions – TimeUnit conversion between Java and Kotlin,
cbrt()
, JavaOptionals
extension functions.Provides a preview for comparable and subtractable
TimeMarks
.Includes experimental extension functions for
java.nio.file.path
.Presents improved kotlin-reflect performance.
Updated JVM compilation target
In Kotlin 1.8.0, the standard libraries (kotlin-stdlib
, kotlin-reflect
, and kotlin-script-*
) are compiled with JVM target 1.8. Previously, the standard libraries were compiled with JVM target 1.6.
Kotlin 1.8.0 no longer supports JVM targets 1.6 and 1.7. As a result, you no longer need to declare kotlin-stdlib-jdk7
and kotlin-stdlib-jdk8
separately in build scripts because the contents of these artifacts have been merged into kotlin-stdlib
.
Note that mixing different versions of stdlib artifacts could lead to class duplication or to missing classes. To avoid that, the Kotlin Gradle plugin can help you align stdlib versions.
cbrt()
The cbrt()
function, which allows you to compute the real cube root of a double
or float
, is now Stable.
TimeUnit conversion between Java and Kotlin
The toTimeUnit()
and toDurationUnit()
functions in kotlin.time
are now Stable. Introduced as Experimental in Kotlin 1.6.0, these functions improve interoperability between Kotlin and Java. You can now easily convert between Java java.util.concurrent.TimeUnit
and Kotlin kotlin.time.DurationUnit
. These functions are supported on the JVM only.
Comparable and subtractable TimeMarks
Before Kotlin 1.8.0, if you wanted to calculate the time difference between multiple TimeMarks
and now, you could only call elapsedNow()
on one TimeMark
at a time. This made it difficult to compare the results because the two elapsedNow()
function calls couldn't be executed at exactly the same time.
To solve this, in Kotlin 1.8.0 you can subtract and compare TimeMarks
from the same time source. Now you can create a new TimeMark
instance to represent now and subtract other TimeMarks
from it. This way, the results that you collect from these calculations are guaranteed to be relative to each other.
This new functionality is particularly useful in animation calculations where you want to calculate the difference between, or compare, multiple TimeMarks
representing different frames.
Recursive copying or deletion of directories
We have introduced two new extension functions for java.nio.file.Path
, copyToRecursively()
and deleteRecursively()
, which allow you to recursively:
Copy a directory and its contents to another destination.
Delete a directory and its contents.
These functions can be very useful as part of a backup process.
Error handling
Using copyToRecursively()
, you can define what should happen if an exception occurs while copying, by overloading the onError
lambda function:
When you use deleteRecursively()
, if an exception occurs while deleting a file or folder, then the file or folder is skipped. Once the deletion has completed, deleteRecursively()
throws an IOException
containing all the exceptions that occurred as suppressed exceptions.
File overwrite
If copyToRecursively()
finds that a file already exists in the destination directory, then an exception occurs. If you want to overwrite the file instead, use the overload that has overwrite
as an argument and set it to true
:
Custom copying action
To define your own custom logic for copying, use the overload that has copyAction
as an additional argument. By using copyAction
you can provide a lambda function, for example, with your preferred actions:
For more information on these extension functions, see our API reference.
Java Optionals extension functions
The extension functions that were introduced in Kotlin 1.7.0 are now Stable. These functions simplify working with Optional classes in Java. They can be used to unwrap and convert Optional
objects on the JVM, and to make working with Java APIs more concise. For more information, see What's new in Kotlin 1.7.0.
Improved kotlin-reflect performance
Taking advantage of the fact that kotlin-reflect
is now compiled with JVM target 1.8, we migrated our internal cache mechanism to Java's ClassValue
. Previously we only cached KClass
, but we now also cache KType
and KDeclarationContainer
. These changes have led to significant performance improvements when invoking typeOf()
.
Documentation updates
The Kotlin documentation has received some notable changes:
Revamped and new pages
Gradle overview – learn how to configure and build a Kotlin project with the Gradle build system, available compiler options, compilation, and caches in the Kotlin Gradle plugin.
Nullability in Java and Kotlin – see the differences between Java's and Kotlin's approaches to handling possibly nullable variables.
Lincheck guide – learn how to set up and use the Lincheck framework for testing concurrent algorithms on the JVM.
New and updated tutorials
Get started with Gradle and Kotlin/JVM – create a console application using IntelliJ IDEA and Gradle.
Create a multiplatform app using Ktor and SQLDelight – create a mobile application for iOS and Android using Kotlin Multiplatform Mobile.
Get started with Kotlin Multiplatform – learn about cross-platform mobile development with Kotlin and create an app that works on both Android and iOS.
Install Kotlin 1.8.0
IntelliJ IDEA 2021.3, 2022.1, and 2022.2 automatically suggest updating the Kotlin plugin to version 1.8.0. IntelliJ IDEA 2022.3 will have the 1.8.0 version of the Kotlin plugin bundled in an upcoming minor update.
For Android Studio Electric Eel (221) and Flamingo (222), version 1.8.0 of the Kotlin plugin will be delivered with the upcoming Android Studios updates. The new command-line compiler is available for download on the GitHub release page.
Compatibility guide for Kotlin 1.8.0
Kotlin 1.8.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 these changes in the Compatibility guide for Kotlin 1.8.0.