Auto Added by WPeMatico

We Are Looking For EAP Champions!

The Kotlin Early Access Preview (EAP) is a program where the Kotlin team ships a few Beta and Release Candidate builds before every release. Any Kotlin developer can participate in the Early Access Preview, try out the latest Kotlin features before they are released, and help the Kotlin team gather the feedback necessary to stabilize a new language version.

While every EAP participant is very helpful, it’s invaluable to have direct contact with people who test each release on the same project. The majority of EAP participants currently use it with hobby projects, so we lack feedback from projects with a huge codebase. To make sure that all scenarios and project types are tested with the new Kotlin version, we’re starting the EAP Champions program – we invite you to join!

EAP Champions are a group of developers who work on large-scale, production-grade projects. For each EAP (Beta and RC) release, the Kotlin Release Management team will ask the EAP champions to test the new Kotlin version and share if they found any problems, performance regressions, or questionable behavior. All communications will happen on the #Kotlinlang Slack channel.

You can become an EAP champion if you:

  • Work on a project that has the relevant attributes:
    • 100+ module Android projects.
    • 100+ module server-side projects with Ktor and Spring.
    • Production projects that have KMM modules.
    • Popular JVM/Multiplatform libraries.
  • Are ready to spend a couple of hours over 2 weeks testing each new release.
  • Have already reported issues to YouTrack, or understand how reporting works.
  • Are excited to participate and make an invaluable contribution to Kotlin’s development.

Why is being an EAP champion worthwhile?

  • It’s a great help to the Kotlin team and the community in general.
  • We’ll mention you or your projects in the Kotlin documentation and release blog posts.
  • For each champion who participates in the testing of 4 releases, we’ll send a special “EAP Champion Pack” – unique merch from JetBrains.
  • If you encounter critical problems in your projects, Kotlin engineers will do their best to provide you with assistance in fixing them or finding a workaround.

Fill out the form if you’re ready to participate! The number of EAP Champions is limited.

🥇 BECOME AN EAP CHAMPION 🥇

Continue ReadingWe Are Looking For EAP Champions!

We Are Looking For EAP Champions!

The Kotlin Early Access Preview (EAP) is a program where the Kotlin team ships a few Beta and Release Candidate builds before every release. Any Kotlin developer can participate in the Early Access Preview, try out the latest Kotlin features before they are released, and help the Kotlin team gather the feedback necessary to stabilize a new language version.

While every EAP participant is very helpful, it’s invaluable to have direct contact with people who test each release on the same project. The majority of EAP participants currently use it with hobby projects, so we lack feedback from projects with a huge codebase. To make sure that all scenarios and project types are tested with the new Kotlin version, we’re starting the EAP Champions program – we invite you to join!

EAP Champions are a group of developers who work on large-scale, production-grade projects. For each EAP (Beta and RC) release, the Kotlin Release Management team will ask the EAP champions to test the new Kotlin version and share if they found any problems, performance regressions, or questionable behavior. All communications will happen on the #Kotlinlang Slack channel.

You can become an EAP champion if you:

  • Work on a project that has the relevant attributes:
    • 100+ module Android projects.
    • 100+ module server-side projects with Ktor and Spring.
    • Production projects that have KMM modules.
    • Popular JVM/Multiplatform libraries.
  • Are ready to spend a couple of hours over 2 weeks testing each new release.
  • Have already reported issues to YouTrack, or understand how reporting works.
  • Are excited to participate and make an invaluable contribution to Kotlin’s development.

Why is being an EAP champion worthwhile?

  • It’s a great help to the Kotlin team and the community in general.
  • We’ll mention you or your projects in the Kotlin documentation and release blog posts.
  • For each champion who participates in the testing of 4 releases, we’ll send a special “EAP Champion Pack” – unique merch from JetBrains.
  • If you encounter critical problems in your projects, Kotlin engineers will do their best to provide you with assistance in fixing them or finding a workaround.

Fill out the form if you’re ready to participate! The number of EAP Champions is limited.

🥇 BECOME AN EAP CHAMPION 🥇

Continue ReadingWe Are Looking For EAP Champions!

Kotlin 1.7.20-Beta Released

The Kotlin 1.7.20-Beta release is out! Here are some highlights from this preview version of Kotlin:

Learn more about these features and how to enable them in What’s new in Kotlin 1.7.20-Beta. For the complete list of changes, refer to release notes on GitHub.

Install 1.7.20-Beta to try out these features and report any issues you find to help us improve Kotlin 1.7.20.

Try new features and provide feedback 

These new features are available in the 1.7.20 preview release, Kotlin 1.7.20-Beta. You can easily install it in your IntelliJ IDEA or Android Studio IDE.

Install Kotlin 1.7.20-Beta in any of the following ways:

  • If you use the Early Access Preview update channel, the IDE will suggest automatically updating to 1.7.20-Beta as soon as it becomes available.
  • If you use the Stable update channel, you can change the channel to Early Access Preview at any time by selecting Tools | Kotlin | Configure Kotlin Plugin Updates in your IDE. You’ll then be able to install the latest preview release. Check out these instructions for details.

Help us improve Kotlin

You can always download the latest versions of these IDEs to get extensive support for Kotlin:

  • IntelliJ IDEA for developing Kotlin applications for a variety of platforms.
  • Android Studio for developing Android and cross-platform mobile applications.

Once you’ve installed 1.7.20-Beta, don’t forget to change the Kotlin version to 1.7.20-Beta in your build scripts.

If you run into any problems:

Read more

Continue ReadingKotlin 1.7.20-Beta Released

Kotlin 1.7.20-Beta Released

The Kotlin 1.7.20-Beta release is out! Here are some highlights from this preview version of Kotlin:

Learn more about these features and how to enable them in What’s new in Kotlin 1.7.20-Beta. For the complete list of changes, refer to release notes on GitHub.

Install 1.7.20-Beta to try out these features and report any issues you find to help us improve Kotlin 1.7.20.

Try new features and provide feedback 

These new features are available in the 1.7.20 preview release, Kotlin 1.7.20-Beta. You can easily install it in your IntelliJ IDEA or Android Studio IDE.

Install Kotlin 1.7.20-Beta in any of the following ways:

  • If you use the Early Access Preview update channel, the IDE will suggest automatically updating to 1.7.20-Beta as soon as it becomes available.
  • If you use the Stable update channel, you can change the channel to Early Access Preview at any time by selecting Tools | Kotlin | Configure Kotlin Plugin Updates in your IDE. You’ll then be able to install the latest preview release. Check out these instructions for details.

Help us improve Kotlin

You can always download the latest versions of these IDEs to get extensive support for Kotlin:

  • IntelliJ IDEA for developing Kotlin applications for a variety of platforms.
  • Android Studio for developing Android and cross-platform mobile applications.

Once you’ve installed 1.7.20-Beta, don’t forget to change the Kotlin version to 1.7.20-Beta in your build scripts.

If you run into any problems:

Read more

Continue ReadingKotlin 1.7.20-Beta Released

Preview of Kotlin 1.6.20 With Prototype of Context Receivers, Parallel Compilation on JVM, Incremental Compilation in JS, and More

The first preview of the 1.6.20 release is out! Introducing Kotlin 1.6.20-M1! This preview includes:

Install 1.6.20-M1 to try out these features and report any issues you find to help us improve Kotlin 1.6.20.

Try new features

Prototype of context receivers for Kotlin/JVM

The YouTrack issue about supporting multiple receivers has received a lot of upvotes and positive feedback, so prototyping it became a part of our roadmap. Recently we published the initial design proposal of the feature under the name context receivers. We are now sharing the prototype for Kotlin/JVM.

With Kotlin 1.6.20-M1, you are no longer limited to having one receiver. If you need more, you can make functions, properties, and classes context-dependent (or contextual) by adding context receivers to their declaration. A contextual declaration:

  • Requires all declared context receivers to be present in a caller’s scope as implicit receivers.
  • Brings declared context receivers into its body scope as implicit receivers.
interface LoggingContext {
    val log: Logger // This context provides a reference to a logger 
}

context(LoggingContext)
fun startBusinessOperation() {
    // You can access the log property since LoggingContext is an implicit receiver
    log.info("Operation has started")
}

fun test(loggingContext: LoggingContext) {
    with(loggingContext) {
        // You need to have LoggingContext in a scope as an implicit receiver
        // to call startBusinessOperation()
        startBusinessOperation()
    }
}

To enable context receivers in your project, use the -Xcontext-receivers compiler option. You can find a detailed description of the feature and its syntax in the KEEP.

Please note that the implementation is a prototype: 

  • With -Xcontext-receivers enabled, the compiler will produce pre-release binaries that cannot be used in production code. 
  • The IDE support for context receivers is now minimal.

Try the feature in your toy projects and share your thoughts and experience with us in this YouTrack issue. If you face any problems, please file a new issue.

Support for parallel compilation of a single module in the JVM backend

We are continuing our work on the roadmap item Improve the new JVM IR backend compilation time. In Kotlin 1.6.20-M1, we added the experimental JVM IR backend mode to compile all the files in a module in parallel. Parallel compilation can reduce the total compilation time by up to 15%.

Enable the experimental parallel backend mode with the compiler option -Xbackend-threads. Use the following arguments for this option:

  • N is equal to the number of threads you want to use. It should not be greater than your number of CPU cores; otherwise, parallelization stops being effective because of switching context between threads.
  • 0 to use one thread for each CPU core. 

This parallelization helps only when the project build is not parallelized enough by a build tool such as Gradle. For example, if you have a very big monolithic module, adding the compiler option -Xbackend-threads to this module may help. But if a project consists of lots of small modules and has a parallelized build, adding another layer of parallelization may hurt performance because of context switching.

Note that experimental parallel compilation doesn’t work with kapt because kapt disables the IR backend. Also note that parallel compilation requires more JVM heap by design. The amount of heap is proportional to the number of threads.

We’d be grateful for your feedback in this YouTrack issue.

Incremental compilation for development binaries with Kotlin/JS IR compiler

To make Kotlin/JS development with the IR compiler more efficient, we’re introducing the new incremental compilation mode.

When building development binaries with the compileDevelopmentExecutableKotlinJs Gradle task in this mode, the compiler caches the results of previous compilations on the module level. It uses the cached compilation results for unchanged source files during subsequent compilations, making them complete faster, especially with small changes. Note that this improvement exclusively targets the development process (shortening the edit-build-debug cycle) and doesn’t affect the building of production artifacts.

To enable incremental compilation for development binaries, add the following line to the project’s gradle.properties:

kotlin.incremental.js.ir=true // false by default

Please tell us what you think of using the incremental compilation with your Kotlin/JS projects: share your results and impressions with us in this YouTrack issue. If you experience problems, file a new issue in YouTrack.

Hierarchical structure support
for multiplatform projects

Kotlin 1.6.20 comes with hierarchical structure support enabled by default. Since introducing it in Kotlin 1.4.0, we’ve significantly improved the frontend and IDE import stability.

Now you can share source code among several similar native targets. The technology will provide correct default dependencies and find the exact API available in the shared code. This eliminates a complex build setup and workarounds to get IDE support for sharing source sets among native targets. It also helps to prevent unsafe API usages meant for a different target.

The technology will come in handy for library authors too. A hierarchical project structure allows you to publish and consume libraries with common APIs for a subset of targets.

Better code-sharing in your project

Without hierarchical structure support, there is no straightforward way to share code across some but not all Kotlin targets. One particular example that is popular: sharing code across all iOS targets and having access to iOS-specific dependencies, like Foundation.

Thanks to the hierarchical project structure support, you can now achieve this out of the box. The Kotlin toolchain will provide the correct default dependencies, like Kotlin/Native stdlib or native libraries.

Moreover, this technology will try its best to find exactly the API surface area available in the shared code. This prevents such cases as, for example, the use of a macOS-specific function in the code shared for Windows.

More opportunities for the library ecosystem

When a multiplatform library is published, the API of its intermediate source sets is now properly published alongside it, making it available for consumers. Again, the Kotlin toolchain will automatically figure out the API available in the consumer source set while watching carefully over unsafe usages, like using an API meant for the JVM in JS code. Learn more about sharing code in libraries.

By default, libraries published with the hierarchical project structure are compatible only with hierarchical structure projects. Learn more about project-library compatibility.

Configuration and setup

Starting with Kotlin 1.6.20-M1, all your new multiplatform projects will have a hierarchical project structure. No additional setup is required.

Leave your feedback

This is a significant change for the whole ecosystem. We appreciate your feedback to help make it even better.

Try it now and report any difficulties you encounter to our issue tracker, YouTrack.

Kotlin/Native performance improvements

We are working hard on Kotlin/Native to speed up the compilation process and improve your developing experience.

This 1.6.20 Kotlin release brings some performance updates and bug fixes that affect the LLVM IR that Kotlin generates. According to the benchmarks on our internal projects, we achieved the following performance boosts on average:

  • 15% reduction in execution time
  • 20% reduction in the code size of both release and debug binaries
  • 26% reduction in the compilation time of release binaries

These changes also provide a 10% reduction in compilation time for a debug binary on a large internal project.

To achieve this, we’ve implemented static initialization for some of the compiler-generated synthetic objects, improved the way we structure LLVM IR for every function, and optimized the compiler caches.

If you have already switched to our new memory manager, which was announced in Kotlin 1.6, you might notice a huge execution time improvement: our benchmarks show 35% improvement on average. Since this EAP release, there is also a concurrent implementation for the sweep phase available for the new memory manager. This should also improve the performance and decrease the duration of garbage collector pauses. Use the -Xgc=cms flag to enable it for the new Kotlin/Native memory manager.
Feel free to share your feedback on the new memory manager performance in this YouTrack issue.

Stay up to date with information about the latest Kotlin features! Enter your email address and subscribe to Kotlin updates using the form to the right of the post.

Try new features and provide feedback

These new features are available in the 1.6.20 preview release – Kotlin 1.6.20-M1. You can easily install it in your IntelliJ IDEA or Android Studio IDE using any of the following ways: 

  • If you use the Early Access Preview update channel, the IDE will suggest updating to 1.6.20-M1 automatically as soon as it becomes available.
  • If you use the Stable update channel, you can change the channel to Early Access Preview at any time by selecting Tools | Kotlin | Configure Kotlin Plugin Updates in your IDE. You’ll then be able to install the latest preview release. Check out these instructions for details. Note that starting from Kotlin 1.6.20-M1, there is only one Early Access Preview channel.

You can always download the latest versions of these IDEs to get extensive support for Kotlin:

  • IntelliJ IDEA for developing Kotlin applications for a variety of platforms.
  • Android Studio for developing Android and cross-platform mobile applications.

Once you’ve installed 1.6.20-M1, change the Kotlin version to 1.6.20-M1 in your build scripts. 

If you run into any problems:

Read more

Continue ReadingPreview of Kotlin 1.6.20 With Prototype of Context Receivers, Parallel Compilation on JVM, Incremental Compilation in JS, and More

Preview of Kotlin 1.6.20 With Prototype of Context Receivers, Parallel Compilation on JVM, Incremental Compilation in JS, and More

The first preview of the 1.6.20 release is out! Introducing Kotlin 1.6.20-M1! This preview includes:

Install 1.6.20-M1 to try out these features and report any issues you find to help us improve Kotlin 1.6.20.

Try new features

Prototype of context receivers for Kotlin/JVM

The YouTrack issue about supporting multiple receivers has received a lot of upvotes and positive feedback, so prototyping it became a part of our roadmap. Recently we published the initial design proposal of the feature under the name context receivers. We are now sharing the prototype for Kotlin/JVM.

With Kotlin 1.6.20-M1, you are no longer limited to having one receiver. If you need more, you can make functions, properties, and classes context-dependent (or contextual) by adding context receivers to their declaration. A contextual declaration:

  • Requires all declared context receivers to be present in a caller’s scope as implicit receivers.
  • Brings declared context receivers into its body scope as implicit receivers.
interface LoggingContext {
    val log: Logger // This context provides a reference to a logger 
}

context(LoggingContext)
fun startBusinessOperation() {
    // You can access the log property since LoggingContext is an implicit receiver
    log.info("Operation has started")
}

fun test(loggingContext: LoggingContext) {
    with(loggingContext) {
        // You need to have LoggingContext in a scope as an implicit receiver
        // to call startBusinessOperation()
        startBusinessOperation()
    }
}

To enable context receivers in your project, use the -Xcontext-receivers compiler option. You can find a detailed description of the feature and its syntax in the KEEP.

Please note that the implementation is a prototype: 

  • With -Xcontext-receivers enabled, the compiler will produce pre-release binaries that cannot be used in production code. 
  • The IDE support for context receivers is now minimal.

Try the feature in your toy projects and share your thoughts and experience with us in this YouTrack issue. If you face any problems, please file a new issue.

Support for parallel compilation of a single module in the JVM backend

We are continuing our work on the roadmap item Improve the new JVM IR backend compilation time. In Kotlin 1.6.20-M1, we added the experimental JVM IR backend mode to compile all the files in a module in parallel. Parallel compilation can reduce the total compilation time by up to 15%.

Enable the experimental parallel backend mode with the compiler option -Xbackend-threads. Use the following arguments for this option:

  • N is equal to the number of threads you want to use. It should not be greater than your number of CPU cores; otherwise, parallelization stops being effective because of switching context between threads.
  • 0 to use one thread for each CPU core. 

This parallelization helps only when the project build is not parallelized enough by a build tool such as Gradle. For example, if you have a very big monolithic module, adding the compiler option -Xbackend-threads to this module may help. But if a project consists of lots of small modules and has a parallelized build, adding another layer of parallelization may hurt performance because of context switching.

Note that experimental parallel compilation doesn’t work with kapt because kapt disables the IR backend. Also note that parallel compilation requires more JVM heap by design. The amount of heap is proportional to the number of threads.

We’d be grateful for your feedback in this YouTrack issue.

Incremental compilation for development binaries with Kotlin/JS IR compiler

To make Kotlin/JS development with the IR compiler more efficient, we’re introducing the new incremental compilation mode.

When building development binaries with the compileDevelopmentExecutableKotlinJs Gradle task in this mode, the compiler caches the results of previous compilations on the module level. It uses the cached compilation results for unchanged source files during subsequent compilations, making them complete faster, especially with small changes. Note that this improvement exclusively targets the development process (shortening the edit-build-debug cycle) and doesn’t affect the building of production artifacts.

To enable incremental compilation for development binaries, add the following line to the project’s gradle.properties:

kotlin.incremental.js.ir=true // false by default

Please tell us what you think of using the incremental compilation with your Kotlin/JS projects: share your results and impressions with us in this YouTrack issue. If you experience problems, file a new issue in YouTrack.

Hierarchical structure support
for multiplatform projects

Kotlin 1.6.20 comes with hierarchical structure support enabled by default. Since introducing it in Kotlin 1.4.0, we’ve significantly improved the frontend and IDE import stability.

Now you can share source code among several similar native targets. The technology will provide correct default dependencies and find the exact API available in the shared code. This eliminates a complex build setup and workarounds to get IDE support for sharing source sets among native targets. It also helps to prevent unsafe API usages meant for a different target.

The technology will come in handy for library authors too. A hierarchical project structure allows you to publish and consume libraries with common APIs for a subset of targets.

Better code-sharing in your project

Without hierarchical structure support, there is no straightforward way to share code across some but not all Kotlin targets. One particular example that is popular: sharing code across all iOS targets and having access to iOS-specific dependencies, like Foundation.

Thanks to the hierarchical project structure support, you can now achieve this out of the box. The Kotlin toolchain will provide the correct default dependencies, like Kotlin/Native stdlib or native libraries.

Moreover, this technology will try its best to find exactly the API surface area available in the shared code. This prevents such cases as, for example, the use of a macOS-specific function in the code shared for Windows.

More opportunities for the library ecosystem

When a multiplatform library is published, the API of its intermediate source sets is now properly published alongside it, making it available for consumers. Again, the Kotlin toolchain will automatically figure out the API available in the consumer source set while watching carefully over unsafe usages, like using an API meant for the JVM in JS code. Learn more about sharing code in libraries.

By default, libraries published with the hierarchical project structure are compatible only with hierarchical structure projects. Learn more about project-library compatibility.

Configuration and setup

Starting with Kotlin 1.6.20-M1, all your new multiplatform projects will have a hierarchical project structure. No additional setup is required.

Leave your feedback

This is a significant change for the whole ecosystem. We appreciate your feedback to help make it even better.

Try it now and report any difficulties you encounter to our issue tracker, YouTrack.

Kotlin/Native performance improvements

We are working hard on Kotlin/Native to speed up the compilation process and improve your developing experience.

This 1.6.20 Kotlin release brings some performance updates and bug fixes that affect the LLVM IR that Kotlin generates. According to the benchmarks on our internal projects, we achieved the following performance boosts on average:

  • 15% reduction in execution time
  • 20% reduction in the code size of both release and debug binaries
  • 26% reduction in the compilation time of release binaries

These changes also provide a 10% reduction in compilation time for a debug binary on a large internal project.

To achieve this, we’ve implemented static initialization for some of the compiler-generated synthetic objects, improved the way we structure LLVM IR for every function, and optimized the compiler caches.

If you have already switched to our new memory manager, which was announced in Kotlin 1.6, you might notice a huge execution time improvement: our benchmarks show 35% improvement on average. Since this EAP release, there is also a concurrent implementation for the sweep phase available for the new memory manager. This should also improve the performance and decrease the duration of garbage collector pauses. Use the -Xgc=cms flag to enable it for the new Kotlin/Native memory manager.
Feel free to share your feedback on the new memory manager performance in this YouTrack issue.

Stay up to date with information about the latest Kotlin features! Enter your email address and subscribe to Kotlin updates using the form to the right of the post.

Try new features and provide feedback

These new features are available in the 1.6.20 preview release – Kotlin 1.6.20-M1. You can easily install it in your IntelliJ IDEA or Android Studio IDE using any of the following ways: 

  • If you use the Early Access Preview update channel, the IDE will suggest updating to 1.6.20-M1 automatically as soon as it becomes available.
  • If you use the Stable update channel, you can change the channel to Early Access Preview at any time by selecting Tools | Kotlin | Configure Kotlin Plugin Updates in your IDE. You’ll then be able to install the latest preview release. Check out these instructions for details. Note that starting from Kotlin 1.6.20-M1, there is only one Early Access Preview channel.

You can always download the latest versions of these IDEs to get extensive support for Kotlin:

  • IntelliJ IDEA for developing Kotlin applications for a variety of platforms.
  • Android Studio for developing Android and cross-platform mobile applications.

Once you’ve installed 1.6.20-M1, change the Kotlin version to 1.6.20-M1 in your build scripts. 

If you run into any problems:

Read more

Continue ReadingPreview of Kotlin 1.6.20 With Prototype of Context Receivers, Parallel Compilation on JVM, Incremental Compilation in JS, and More

Kotlin 1.5.30-RC With Java Toolchains in Gradle, JS IR Backend in Beta, Stdlib Improvements, and More

The 1.5.30 release is approaching, and now we’re presenting the release candidate with the updated opt-in requirements, Kotlin/JS IR backend in Beta, support for Java toolchains in the Gradle plugin, improvements to the Regex and Duration API in the standard library, and more. Try it and report any issues you face to help us prepare the final release.

We’ve unveiled the first set of Kotlin 1.5.30 features with the 1.5.30-M1 preview. In this post, we’ll briefly describe some more of the new features that you can try with Kotlin 1.5.30-RC:

Try new features

Opt-in requirements

Kotlin’s opt-in requirement mechanism has been available in the Experimental state for quite some time, and releasing it as Stable is on our roadmap. In 1.5.30, we’re changing the behavior of the opt-in requirements to make it more consistent and less error-prone:

  • An opt-in is now required for implicit usages of the marked API, for example, if it’s used as a function’s return type.
  • Opt-in annotations are now prohibited on more declarations, including local variables, value parameters, backing fields, and getters.
  • Overriding methods can only have opt-in annotations that are present on their basic declarations.
  • Opt-in annotations can’t have TYPE and TYPE_PARAMETER targets.

Instantiation of annotation classes

The ability to create instances of annotation classes by calling their constructors is another improvement on the Kotlin roadmap. In 1.5.30-RC, we’re adding the opt-in support for this ability to the JVM.

To allow creation of annotation instances with constructors, switch to the language version 1.6 by adding the -language-version 1.6 compiler option. You can find more details about this feature in this KEEP.

JS IR backend in Beta

The IR-based backend for the Kotlin/JS compiler has been in Alpha since Kotlin 1.4.0. We never stopped working on it, and in 1.5.30 it will become Beta. This means that we don’t expect breaking changes anymore and its future development will be mainly focused on stabilization. 

How to migrate

Gradle: Java toolchain support and JVM options for Kotlin daemon in the build script

Gradle 6.7 introduced the support for Java toolchains – an easy way to select a JDK for the project compilation. Just declare the version you need in the build script, and Gradle does the rest, finding it on your host or even downloading and installing it if it’s not there yet.

Kotlin 1.5.30-RC enables Java toolchain support for Kotlin compilation tasks:

kotlin {
    toolchain {
        (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)
    }
}

Other Gradle-related improvements include new ways to provide JVM options for the Kotlin Gradle daemon. Now you can specify them in a separate line in gradle.properties:

kotlin.daemon.jvmargs = "-Xmx486m -Xms256m -XX:+UseG1GC"

or in build.gradle.kts:

kotlin {
   kotlinDaemonJvmArgs = listOf("-Xmx486m", "-Xms256m", "-XX:+UseG1GC")
}

Regex and Duration API improvements

Kotlin’s Regex API is receiving new experimental functions:

  • matchesAt() checks if a regex has a match in the specified position of a String. It’s accompanied by matchAt() that returns the match itself if it is found.
val releaseText = "Kotlin 1.5.30 is coming!"
// regular expression: one digit, dot, one digit, dot, one or more digits
val versionRegex = "\d[.]\d[.]\d+".toRegex()
println(versionRegex.matchesAt(releaseText, 7)) // "true"
println(versionRegex.matchAt(releaseText, 7)?.value) // "1.5.30"
  • splitToSequence() – a lazy counterpart of split() –  splits the string around matches of the given regex, but returns the result as a Sequence. A similar function is also added to CharSequence.
val phoneNumber = "+7 (123) 456-78-90"
val regex = "[ ()-]+".toRegex()
val parts = phoneNumber.splitToSequence(regex)
// or
// val parts = regex.splitToSequence(phoneNumber)

// any processing operation on parts are executed lazily

The experimental Duration API has also been updated in 1.5.30-RC:

  • The output of Duration.toString() has become more readable. For example, Duration.minutes(2415).toString() produces 1d 16h 15m instead of 40.3h.
  • Duration also receives new functions for parsing from strings:
    • parse() parses Duration objects from strings formatted as Duration’s toString() or strings representing ISO 8601 durations (such as toIsoString() outputs).
    • parseIsoString() parses Duration objects from strings representing ISO 8601 durations. Both parsing functions come with *OrNull() counterparts.
import kotlin.time.Duration
import kotlin.time.ExperimentalTime

@ExperimentalTime
fun main(){
    val isoFormatString = "PT1H30M"
    val defaultFormatString = "1d 1h 15m"
    println(Duration.parseIsoString(isoFormatString)) // "1h 30m"
    println(Duration.parse(defaultFormatString)) // "1d 1h 15m"
    //println(Duration.parseIsoString(defaultFormatString)) // throws exception
    println(Duration.parseIsoStringOrNull(defaultFormatString)) // "null"
}

Try the new features and report issues

All Kotlin 1.5.30 features (including those presented in the 1.5.30-M1 preview) are available in the release candidate 1.5.30-RC. You can easily install it in your IDE – IntelliJ IDEA or Android Studio – in any of these ways: 

  • If you use the Early Access Preview update channel, the IDE will suggest updating to 1.5.30-RC automatically once it is out.
  • If you use the Stable update channel, you can change the channel to Early Access Preview at any time by selecting Tools | Kotlin | Configure Kotlin Plugin Updates in your IDE, then you’ll be able to install the latest preview release. Check out these instructions for details.

You can always download the latest versions of these IDEs to get extensive support for Kotlin:

  • IntelliJ IDEA for developing Kotlin applications for a variety of platforms.
  • Android Studio for developing Android and cross-platform mobile applications.

Note: the latest version of IntelliJ IDEA – 2021.2 – doesn’t support Kotlin 1.5.30 previews. If you have already upgraded to this version, you can easily install the previous version (2021.1) using the JetBrains Toolbox App and try Kotlin 1.5.30-RC in that version.

Once you’ve installed 1.5.30-RC, change the Kotlin version to 1.5.30-RC in your build scripts. 

If you run into any problems:

Read more

Continue ReadingKotlin 1.5.30-RC With Java Toolchains in Gradle, JS IR Backend in Beta, Stdlib Improvements, and More

Preview of Kotlin 1.5.30 With Native Apple Silicon Support, Improved Kotlin DSL for the CocoaPods Gradle Plugin, and More

Be the first to try the new features and improvements coming in Kotlin 1.5.30: native Apple silicon support, an improved Kotlin DSL for Cocoapods configuration, the ability to share custom native libraries across platforms in multiplatform applications, a better debugging experience for applications with the Kotlin/JS IR backend, and more.

These features are available as part of an early access preview of 1.5.30. Install 1.5.30-M1 to get your hands on them.

For the Kotlin Early Access Preview, we ship a few milestone builds before every release. You can install these builds and try features and improvements before they go live.

You can help us make Kotlin better by reporting any issues you encounter and providing feedback to our issue tracker, YouTrack.

It is very likely that we’ll be able to fix reported issues before the final release, which means you won’t need to wait until the next version of Kotlin for your issues to be addressed.

This blog post provides an overview of the following features shipped in 1.5.30-M1:

Try new features

Native support for Apple silicon

Previously, if you wanted to build and run Kotlin applications on Apple silicon hosts, you had to use the Rosetta translation environment. With 1.5.30, this is no longer necessary. You can build applications for all targets on Apple silicon hardware naturally without this environment.

New targets introduced in 1.5.30 – macosArm64, iosSimulatorArm64, watchosSimulatorArm64, and tvosSimulatorArm64 – make it possible to run Kotlin code on Apple silicon natively. 

Note that due to limited support for these new targets in 1.5.30, they can’t be run using target shortcuts. We are working on improving support for these targets. 

Improved Kotlin DSL for the CocoaPods Gradle plugin

Kotlin 1.5.30 improves CocoaPods configuration by providing a new DSL format and new parameters for: 

  • Defining the dynamic or static version of the framework
  • Enabling export dependencies explicitly
  • Enabling Bitcode embedding
cocoapods {
    frameworkName = "MyFramework" //This property is deprecated and will be removed in future versions
    //new DSL for framework configuration
    framework {
        //All Framework properties are supported
        //Framework name configuration. Use this property instead of deprecated 'frameworkName'
        baseName = "MyFramework"
        //Dynamic framework support
        isStatic = false
        //Dependency export
        export(project(":anotherKMMModule"))
        transitiveExport = true
        //Bitcode embedding
        embedBitcode(BITCODE)
    }
}

Sharing custom cinterop libraries across platforms in multiplatform applications

Previously, when creating multiplatform applications you could share only native platform-dependent libraries shipped with Kotlin/Native.

With Kotlin 1.5.30, you can also share custom native libraries that are configured using the cinterops block of the build script.

To enable this support, add kotlin.mpp.enableCInteropCommonization=true to your gradle.properties.

kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false
kotlin.mpp.enableCInteropCommonization=true

Better debugging for applications with Kotlin/JS IR backend 

Kotlin 1.5.30 improves the debugging experience for Kotlin/JS applications with the new IR backend by generating JavaScript source maps. Now you can enjoy a better debugging experience with breakpoints, stepping, variable inspections, and readable stack traces with proper source references in any JavaScript debugger.  

Learn more about debugging Kotlin/JS applications.

Please note that, because of internal changes, Kotlin/JS IR compiler 1.5.30 and its previews work only with the standard library of the same version. And vice versa, the 1.5.30 Kotlin/JS standard library can be used only with the same version of the IR compiler. This restriction does not apply to the default (legacy) compiler or any other libraries.

Try new features and provide feedback

These new features are available in the 1.5.30 preview release – Kotlin 1.5.30-M1. You can easily install it in your IDE – IntelliJ IDEA or Android Studio – in any of these ways: 

  • If you use the Early Access Preview update channel, the IDE will suggest updating to 1.5.30-M1 automatically once it is out.
  • If you use the Stable update channel, you can change the channel to Early Access Preview at any time by selecting Tools | Kotlin | Configure Kotlin Plugin Updates in your IDE, then you’ll be able to install the latest preview release. Check out these instructions for details.

You can always download the latest versions of these IDEs to get extensive support for Kotlin:

  • IntelliJ IDEA for developing Kotlin applications for a variety of platforms.
  • Android Studio for developing Android and cross-platform mobile applications.

Once you’ve installed 1.5.30-M1, change the Kotlin version to 1.5.30-M1 in your build scripts. 

If you run into any problems, please refer to these instructions.

Read more

Continue ReadingPreview of Kotlin 1.5.30 With Native Apple Silicon Support, Improved Kotlin DSL for the CocoaPods Gradle Plugin, and More

Dokka Preview Based on Kotlin 1.4.0-RC

The following post is written by Paweł Marks and Kamil Doległo.

Every programming ecosystem needs documentation to thrive. Kotlin has its roots in the JVM ecosystem, where Javadoc is a standard and universally accepted documentation engine. It was only natural to expect Kotlin to have a similarly seamless tool. That was the initial goal of Dokka – to provide a reliable and simple documentation engine. But the increasing diversity of Kotlin, with features like multiplatform projects, Native support, and so on, requires Dokka to be more complex.
The ongoing development of Kotlin 1.4 gave us a chance to rethink, redesign, and reimplement Dokka from scratch (its version number is now aligned with the Kotlin embedded compiler). In this post, we give you an overview of Dokka’s new features and announce its preview release. We would appreciate it if you could try the preview and share your feedback.

file

How to Try

Dokka is distributed as a plugin for two of the most popular Kotlin build tools – Maven and Gradle. For advanced use cases, Dokka can be used as a standalone command-line application. For a Gradle-based project, just add the following to your project’s build.gradle or build.gradle.kts files:

plugins {
    id("org.jetbrains.dokka") version "1.4.0-rc"
}

repositories {
    jcenter()
}

After running ./gradlew dokkaHtml you should see generated documentation in the dokka directory inside your project’s build directory.

New HTML format

One of our main goals was to produce good-looking, modern documentation without any need for tweaking and configuration from the user. That is why the default look of Dokka is no longer a simple static web page. Let’s take a quick look at the most important features of the new HTML format. Note that we’ve used the coroutines documentation to demonstrate the new Dokka format, but we won’t actually be converting this documentation until a later time.

Navigation tree

On the left side of your screen, you can see all your project modules, packages, and types organized in a hierarchical menu. This allows you to not only see the project structure at a glance, but also to quickly navigate between different parts of your codebase.

Search bar

If your project is particularly complex, or you don’t know its codebase structure and you need to find some type or function, you can use the built-in search bar. It knows all symbols in the project so it can offer IDE-like autocompletion for search queries.

Linking to sources

Dokka can link from any symbol to its definition in code if your project’s code is hosted online. Just configure your repo URL using the sourceLink option as a generation parameter and all your functions and types will get links pointing to the exact line of code where each of them was defined.

Information about platforms

Kotlin is a multiplatform language and its documentation engine needs to reflect all platform information that can be important for end-users. In the documentation for a multiplatform project, you will notice that every symbol is marked with a badge indicating to which platform it applies. Moreover, if there are any differences between documentation or signatures of the same symbol on different platforms you can use the tabs to switch between them.

On every page you can choose to show or hide symbols defined in specific platforms.

Runnable samples

Kotlin has a great tool called Kotlin Playground that allows you to run simple code snippets from your browser. This tool is now also integrated with Dokka. You can specify the source of your samples and they will be included in your documentation, allowing end users to check how to properly use your library. All you have to do is create an ordinary Kotlin file with your code, include it in the documentation using
samples = listOf(<paths to the files>)
and link to the desired method using
@sample <fully qualified name of your method>
and Dokka will automatically copy the source code and use it to create a runnable block.

Other formats

Markdown

If you want to host your documentation on GitHub pages or other sites that use markdown formatting, Dokka has that covered. Out of the box, it supports two different flavors of Markdown – Jekyll and GFM (GitHub Flavored Markdown). To use them you only need to run dokkaJekyll or dokkaGfm task.

Kotlin-as-java and javadoc

Kotlin is interoperable with Java, which means that Kotlin libraries that target the JVM can be used from Java projects. Dokka can generate documentation for them too. You just need to include dokkaHtmlPlugin("org.jetbrains.dokka:kotlin-as-java-plugin:1.4.0-rc") for HTML format or dokkaGfmPlugin(...) or dokkaJekyllPlugin(...) for GFM and Jekyll formats respectively. You will see your classes and functions in a Java-like format, for example, class properties will be changed to the appropriate get and set methods. Thanks to our new architecture, the Kotlin-as-java plugin works with HTML, GFM, and Jekyll Markdown, as well as some user-defined formats.

You can go one step further and not only desugar your properties to getters and setters but also generate documentation in the same way as Javadoc does. You just need to run the dokkaJavadoc task. The new Javadoc generation is completely independent of JDK artifacts, so it is guaranteed to work with every modern version of JDK (8 and newer).

Multimodule projects

By default, Dokka generates one set of documentation per Kotlin module.

  • Run the dokkaHtmlCollector task to collect all definitions for all modules and document them as if they were a single module. This way the code can be divided into small modules while still having one documentation set.
  • Run the dokkaHtmlMultimodule task to generate documentation for each module in a separate directory and then create a common page with an index that links to all modules with brief previews of their documentation. You can customize this page by providing your own template in a Markdown file.

Other features

Even though Dokka 1.4 is completely rewritten, we wanted to preserve all the useful features and configuration options from previous releases. You can still:

  • Generate documentation for mixed Java and Kotlin sources.
  • Include Markdown documentation for the project, module, and package pages.
  • Generate documentation for non-public symbols.
  • Receive a report after generation about each undocumented symbol.
  • Specify all generation options on a per-package basis.

Pluggability

The new Dokka has a flexible and powerful plugin system. Jekyll, GFM, kotlin-as-java, and Javadoc are only a few examples of plugins that can be created for the new Dokka. Everyone can now provide a custom format or transform the documentation in any way imaginable. Thanks to its robust framework it is intuitive to use and hard to accidentally break something. If you are interested in plugin development, check out our developers’ guide.

Continue ReadingDokka Preview Based on Kotlin 1.4.0-RC

Kotlin 1.4.0-RC: Debugging coroutines

We continue to highlight the upcoming changes in 1.4 release. In this blogpost, we want to describe a couple of important features related to coroutines:

  • New functionality to conveniently debug coroutines
  • The ability to define deep recursive functions

These changes are already available for you to try in the 1.4.0-RC release!

Let’s dive into details.

Debugging coroutines

Coroutines are great for asynchronous programming (but not only for that), and many people already use them or are starting to use them. When you write code with coroutines, however, trying to debug them can be a real pain. Coroutines jump between threads. It can be difficult to understand what a specific coroutine is doing or to check its context. And in some cases, tracking steps over breakpoints simply doesn’t work. As a result, you have to rely on logging or mental effort to debug the code with coroutines. To address this issue, we’re introducing new functionality in the Kotlin plugin that aims to make debugging coroutines much more convenient.

The Debug Tool Window now contains a new Coroutines tab. It is visible by default, and you can switch it on and off:

In this tab, you can find information about both currently running and suspended coroutines. The coroutines are grouped by the dispatcher they are running on. If you started a coroutine with a custom name, you can find it by this name in the Tool Window. In the following example, you can see that the main coroutine is running (we’ve stopped on a breakpoint inside it), and the other four coroutines are suspended:

import kotlinx.coroutines.*

fun main() = runBlocking {
   repeat(4) {
       launch(Dispatchers.Default + CoroutineName("Default-${'a' + it}")) {
           delay(100)
           val name = coroutineContext[CoroutineName.Key]?.name
           println("I'm '$name' coroutine")
       }
   }
   delay(50)
   // breakpoint
   println("I'm the main coroutine")
}

With the new functionality, you can check the state of each coroutine and see the values of local and captured variables. This also works for suspended coroutines!

In this example, we check the values of the local variables of suspended coroutines:

import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
   launch {
       val a = 3
       delay(300)
       println(a)
   }
   launch {
       val b = 2
       delay(200)
       println(b)
   }
   launch {
       val c = 1
       delay(100)
       // breakpoint here:
       println(c)
   }
}

Choose a suspended coroutine (click invokeSuspend to see its state on that point) and the Variables tab will show you the state of the local variables:

You can now see a full coroutine creation stack, as well as a call stack inside the coroutine:

Use the ‘Get Coroutines Dump’ option to get a full report containing the state of each coroutine and its stack:

At the moment, the coroutines dump is still rather simple, but we’re going to make it more readable and helpful in future versions.

Note that to make the debugger stop at a given breakpoint inside a coroutine, this breakpoint should have the “Suspend: All” option chosen for it:

To try this new functionality for debugging coroutines, you need to use the latest version of kotlinx.coroutines, 1.3.8-1.4.0-rc, and the latest version of the Kotlin plugin (e.g. 1.4.0-rc-release-IJ2020.1-2).

The functionality is available only for Kotlin/JVM. If you encounter any problems (please don’t forget to share the details with us!), you can switch it off by opening Build, Execution, Deployment | Debugger | Data Views | Kotlin in Preferences and choosing Disable coroutines agent. For now, we’re releasing this functionality for debugging coroutines in the experimental state, and we’re looking forward to your feedback!

Defining deep recursive functions using coroutines

In Kotlin 1.4, you can define recursive functions and invoke them even when the call depth is greater than 100,000, using the standard library support based on coroutines!

Let’s first look at an ordinary recursive function, whose usage results in a StackOverflowError when the recursion depth gets too high. After that, we’ll discuss how you can fix the problem and rewrite the function using the Kotlin standard library.

We’ll use a simple binary tree, where each Tree node has a reference to its left and right children:

class Tree(val left: Tree?, val right: Tree?)

The depth of the tree is the length of the longest path from its root to its child nodes. It can be computed using the following recursive function:

fun depth(t: Tree?): Int =
   if (t == null) 0 else maxOf(
       depth(t.left),
       depth(t.right)
   ) + 1

The tree depth is the maximum of the depths of the left and right children increased by one. When the tree is empty it’s zero.

This function works fine when the recursion depth is small:

class Tree(val left: Tree?, val right: Tree?)

fun depth(t: Tree?): Int =
   if (t == null) 0 else maxOf(
       depth(t.left),
       depth(t.right)
   ) + 1

fun main() {
//sampleStart
    val tree = Tree(Tree(Tree(null, null), null), null)
    println(depth(tree)) // 3
//sampleEnd
}

However, if you create a tree with a depth greater than 100,000, which in practice is not so uncommon, you’ll get StackOverflowError as a result:

class Tree(val left: Tree?, val right: Tree?)

fun depth(t: Tree?): Int =
   if (t == null) 0 else maxOf(
       depth(t.left),
       depth(t.right)
   ) + 1
//sampleStart
fun main() {
   val n = 100_000
   val deepTree = generateSequence(Tree(null, null)) { prev ->
       Tree(prev, null)
   }.take(n).last()

   println(depth(deepTree))
}
/*
Exception in thread "main" java.lang.StackOverflowError
  at FileKt.depth(File.kt:5)
  ...
*/
//sampleEnd

The problem is that the call stack gets too large. To solve this issue, you can use a VM option to increase the maximum stack size. However, while this might work for specific use cases, it’s not a practical solution for the general case.

Alternatively, you can rewrite the code and store results for intermediate calls by hand in the heap rather than on the stack. This solution works in most cases and is common in other languages. However, the resulting code becomes non-trivial and complicated, and the beauty and simplicity of the initial function are lost. You can find an example here.

Kotlin now provides a clean way to solve this problem based on the coroutines machinery.

The Kotlin library now includes the definition DeepRecursiveFunction, which models recursive calls using the suspension mechanism:

class Tree(val left: Tree?, val right: Tree?)

@OptIn(ExperimentalStdlibApi::class)
val depthFunction = DeepRecursiveFunction<Tree?, Int> { t ->
   if (t == null) 0 else maxOf(
       callRecursive(t.left),
       callRecursive(t.right)
   ) + 1
}

@OptIn(ExperimentalStdlibApi::class)
fun depth(t: Tree) = depthFunction(t)

fun main() {
   val n = 100_000
   val deepTree = generateSequence(Tree(null, null)) { prev ->
       Tree(prev, null)
   }.take(n).last()

   println(depth(deepTree)) // 100000
}

You can compare the two versions, the initial one and the one using DeepRecursiveFunction, to make sure that the logic remains the same. Your new function now becomes a variable of type DeepRecursiveFunction, which you can call using the ‘invoke’ convention as depthFunction(t). The function body now becomes the body of the lambda argument of DeepRecursiveFunction, and the recursive call is replaced with callRecursive. These changes are straightforward and easy to make. Note that while the new depth function uses coroutines under the hood, it is not itself a suspend function.

Understanding how DeepRecursiveFunction is implemented is interesting, but it is not necessary in order for you to use it and benefit from it. You can find the implementation details described in this blog post.

DeepRecursiveFunction is a part of the Kotlin standard library, not part of the kotlinx.coroutines library, since it’s not about asynchronous programming. At the moment this API is still experimental, so we’re looking forward to your feedback!

How to try it

As always, you can try Kotlin online at play.kotl.in.

In IntelliJ IDEA and Android Studio, you can update the Kotlin Plugin to version 1.4.0-RC. See how to do this.

If you want to work on existing projects that were created before installing the preview version, you need to configure your build for the preview version in Gradle or Maven. Note that unlike the previous preview versions, Kotlin 1.4.0-RC is also available directly from Maven Central. This means you won’t have to manually add the kotlin-eap repository to your build files.

You can download the command-line compiler from the Github release page.

Share your feedback

We’ll be very thankful if you find and report bugs to our issue tracker. We’ll try to fix all the important issues before the final release, which means you won’t need to wait until the next Kotlin release for your issues to be addressed.

You are also welcome to join the #eap channel in Kotlin Slack (get an invite here). In this channel, you can ask questions, participate in discussions, and get notifications about new preview builds.

Let’s Kotlin!

Continue ReadingKotlin 1.4.0-RC: Debugging coroutines

Kotlin 1.4.0-RC Released

We’re almost there! We’re happy to unveil Kotlin 1.4.0-RC – the release candidate for the next major version of our programming language. Read on to learn about what has changed in Kotlin 1.4.0-RC, and make sure to try its new features before they are officially released with Kotlin 1.4.0.

A special thanks to everyone who tried our milestone releases (1.4-M1, 1.4-M2, and 1.4-M3), shared their feedback, and helped us improve this version of Kotlin!

This post highlights the new features and key improvements that are available in Kotlin 1.4.0-RC:

Improved *.gradle.kts IDE support

We significantly improved the IDE support for Gradle Kotlin DSL scripts (*.gradle.kts files) in Kotlin 1.3.70, and we’ve continued to improve it for Kotlin 1.4.0-RC. Here is what this new version brings:

Loading script configuration explicitly for better performance

Previously, when you added a new plugin to the buildscript or plugins block of your build.gradle.kts, the new script configuration was loaded automatically in the background. Then, after it was applied, you could use code assistance for the newly added plugin.

To improve performance, we’ve removed this automatic behavior of applying changes to the script configuration upon typing. For Gradle 6.0 and above, you need to explicitly apply changes to the configurations by clicking Load Gradle Changes or by reimporting the Gradle project.

In earlier versions of Gradle, you need to manually load the script configuration by clicking Load Configuration in the editor.

We’ve added one more action in IntelliJ IDEA 2020.1 with Gradle 6.0+, Load Script Configurations, which loads changes to the script configurations without updating the whole project. This takes much less time than reimporting the whole project.

Better error reporting

Previously you could only see errors from the Gradle Daemon (a process that runs in the background and is responsible for all Gradle-related tasks and activities) in separate log files. Now if you use Gradle 6.0 or above, the Gradle Daemon returns all the information about errors directly and shows it in the Build tool window. This saves you both time and effort.

Less boilerplate in your project’s configuration

With improvements to the Kotlin Gradle plugin, you can write less code in your Gradle build files: one of the most common scenarios is now enabled by default.

Making the standard library a default dependency

An overwhelming majority of projects require the Kotlin standard library. Starting from 1.4.0-RC, you no longer need to declare a dependency on stdlib in each source set manually — it will now be added by default. The automatically added version of the standard library will be the same as the version of the Kotlin Gradle plugin, since they have the same versioning.

This is how a typical multiplatform project configuration with Android, iOS, and JavaScript targets looked before 1.4:

...

android()
ios()
js()

sourceSets {
    commonMain {
        dependencies {
            implementation("org.jetbrains.kotlin:kotlin-stdlib-common")
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.3.6")
        }
    }
   
    androidMain {
        dependencies {
            implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.6")
        }
    }

    jsMain {
        dependencies {
            implementation("org.jetbrains.kotlin:kotlin-stdlib-js")
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.3.6")
        }
    }

    iosMain {
        dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-native:1.3.6")
        }
    }
}

...

Now, you don’t need to explicitly declare a dependency on the standard library at all, and with hierarchical project structure support, announced in 1.4-M2, you have to specify other dependencies only once. So your Gradle build file will become much more concise and easy to read:

...

android()
ios()
js()

sourceSets {
    commonMain {
        dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6")
        }
    }
}

...

For platform source sets and backend-shared source sets, the corresponding standard library will be added, while a common standard library will be added to the rest. The Kotlin Gradle plugin will select the appropriate JVM standard library depending on the kotlinOptions.jvmTarget setting.

If you declare a standard library dependency explicitly (for example, if you need a different version), the Kotlin Gradle plugin won’t override it or add a second standard library. And if you do not need a standard library at all, you can add the opt-out flag to the Gradle properties:

kotlin.stdlib.default.dependency=false

Kotlin/Native

Simplified management of CocoaPods dependencies

Previously, once you integrated your project with the dependency manager CocoaPods, you could build an iOS, macOS, watchOS, or tvOS part of your project only in Xcode, separate from other parts of your multiplatform project. These other parts could be built in IntelliJ IDEA.

Moreover, every time you added a dependency on an Objective-C library stored in CocoaPods (Pod library), you had to switch from IntelliJ IDEA to Xcode, run the task pod install, and run the Xcode build there.

Now you can manage Pod dependencies right in IntelliJ IDEA while enjoying the benefits it provides for working with code, such as code highlighting and completion. You can also build the whole Kotlin project with Gradle, without having to switch to Xcode. This means you only have to go to Xcode when you need to write Swift/Objective-C code or run your application on a simulator or device.

Now you can also work with Pod libraries stored locally.

Depending on your needs, you can add dependencies between:

  • A Kotlin project and Pod libraries from the CocoaPods repository.
  • A Kotlin project and Pod libraries stored locally.
  • A Kotlin Pod (Kotlin project used as a CocoaPods dependency) and an Xcode project with one or more targets.

Complete the initial configuration, and when you add a new dependency to CocoaPods, just re-import the project in IntelliJ IDEA. The new dependency will be added automatically. No additional steps are required.

Below you can find instructions on how to add dependencies on Pod libraries from the CocoaPods repository. The Kotlin 1.4 documentation will cover all scenarios.

How to use the CocoaPods integration

Install the CocoaPods dependency manager and plugin
  1. Install the cocoapods dependency manager (sudo gem install cocoapods).
  2. Install the cocoapods-generate plugin (sudo gem install cocoapods-generate).
  3. In the build.gradle(.kts) file of your project, apply the CocoaPods plugin with kotlin("native.cocoapods"):
    plugins {
       kotlin("multiplatform") version "1.4.0-rc"
       kotlin("native.cocoapods") version "1.4.0-rc"
    }
    
Add dependencies on Pod libraries from the CocoaPods repository
  1. Add dependencies on Pod libraries that you want to use from the CocoaPods repository with pod().
    You can also add dependencies as subspecs.

    kotlin {
        ios()
    
        cocoapods {
            summary = "CocoaPods test library"
            homepage = "https://github.com/JetBrains/kotlin"
            pod("AFNetworking", "~> 4.0.0")
    
            //Remote Pod added as a subspec
            pod("SDWebImage/MapKit")
        }
    }
    
  2. Re-import the project.
    To use dependencies from Kotlin code, import the packages:

    import cocoapods.AFNetworking.*
    import cocoapods.SDWebImage.*
    

We’re also happy to share a sample project with you that demonstrates how to add dependencies on Pod libraries stored both remotely in the CocoaPods repository and locally.

Generate release .dSYMs on Apple targets by default

Debugging an iOS application crash sometimes involves analyzing crash reports, and crash reports generally require symbolication to become properly readable. To symbolicate addresses in Kotlin, the .dSYM bundle for Kotlin code is required. Starting with 1.4-M3, the Kotlin/Native compiler produces .dSYMs for release binaries on Darwin platforms by default. This can be disabled with the -Xadd-light-debug=disable compiler flag. On other platforms, this option is disabled by default. To toggle this option in Gradle, use:

kotlin {
    targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
        binaries.all {
            freeCompilerArgs += "-Xadd-light-debug={enable|disable}"
        }
    }
}

Performance improvements

We continue to focus on optimizing the overall performance of the Kotlin/Native development process:

  • In 1.3.70 we introduced two new features for improving the performance of Kotlin/Native compilation: caching project dependencies and running the compiler from the Gradle daemon. Thanks to your feedback, we’ve managed to fix numerous issues and improve the overall stability of these features, and we will continue to do so.
  • There are also some runtime performance improvements as well. Overall runtime performance has improved because of optimizations in GC. This improvement will be especially apparent in projects with a large number of long-lived objects. HashMap and HashSet collections now work faster by escaping redundant boxing.

Kotlin/JS

With Kotlin 1.4.0-RC, we are making the @JsExport annotation compatible with the default compiler backend. We are also providing more robust and fine-grained control over npm dependency management and the Dukat integration for Gradle projects, refining our support for CSS, and offering a first look at our integration with the Node.js APIs, among other things.

@JsExport annotation for default compiler backend

In the previous milestones for Kotlin 1.4, we introduced the @JsExport annotation, which is used to make a top-level declaration available from JavaScript or TypeScript when using the new IR compiler backend. Starting with Kotlin 1.4-M3, it is now also possible to use this annotation with the current default compiler backend. Annotating a top-level declaration with @JsExport when using the current default compiler backend turns off name mangling for the declaration. Having this annotation in both compiler backends allows you to transition between them without having to adjust your logic for exporting top-level declarations. Please note that the generation of TypeScript definitions is still only available when using the new IR compiler backend.

Changes to npm dependency management

Explicit version requirement for dependency declarations

Declaring dependencies on npm packages without specifying a version number makes it harder to reliably manage the packages you use. This is why you are required from now on to explicitly specify a version or version range based on npm’s semver syntax for dependencies. The Gradle DSL now also supports multiple ranges for dependencies, allowing you to pinpoint exactly which versions you want to accept in your project, for example:

dependencies {
    implementation(npm("react", "> 14.0.0 <=16.9.0))
}

Additional types of npm dependencies

Besides regular dependencies from npm, which you can specify using npm(...) inside your dependencies block, there are now three more types of dependencies that you can use:

To learn more about when each type of dependency can best be used, have a look at the official documentation linked from npm.

Automatic inclusion and resolution of transitive npm dependencies

Previously, if you depended on a library whose author did not manually add a package.json file to its artifacts, you would sometimes be required to manually import its npm dependencies. This was the case for kotlinx.serialization, for example, which required you to include text-encoding and abort-controller as dependencies in your Gradle build file for the package to work on Kotlin/JS.

Now the Gradle plugin automatically generates package.json files for libraries, and includes them in the jar or klib artifacts. When including a library of this sort, the file is automatically parsed and the required dependencies are automatically included, removing the need to add them to your Gradle build file manually.

Adjustments for CSS support

With Kotlin 1.4-M2, we introduced support for webpack’s CSS and style loaders directly from Gradle via cssSettings. In order to more closely reflect its actual tasks and effects, we have since renamed the configuration parameter to cssSupport. Going forward, the Gradle plugin no longer enables CSS support by default – a setting we had experimented with in 1.4-M2. We hope that this change will prevent confusion for those who include their own settings for how style sheets should be handled (for example by using Sass or Less loaders). In these situations, it would not be immediately obvious that a project’s default configuration already injects some CSS settings that could lead to a conflict.

To turn on CSS support in your project, set the cssSupport.enabled flag in your Gradle build file for webpackTask, runTask, and testTask. When creating a new project using the wizards included in IntelliJ IDEA, these settings will automatically be included in the generated build.gradle(.kts) file:

webpackTask {
   cssSupport.enabled = true
}
runTask {
   cssSupport.enabled = true
}
testTask {
   useKarma {
      // . . .
      webpackConfig.cssSupport.enabled = true
   }
}

We realize that having to adjust these settings individually for each task is not very convenient. We are looking at adding a central point of configuration for cssSupport in the plugin’s DSL (you can follow our progress here).

Improvements for Dukat integration

The Kotlin/JS Gradle plugin adds more fine-grained control to its integration with Dukat, the tool for automatically converting TypeScript declaration files (.d.ts) into Kotlin external declarations. You now have two different ways to select if and when Dukat should generate declarations:

Generating external declarations at build time

The npm dependency function now takes a third parameter after the package name and version: generateExternals. This allows you to individually control whether Dukat should generate declarations for a specific dependency, like so:

dependencies {
  implementation(npm("decamelize", "4.0.0", generateExternals = true))
}

You can use the kotlin.js.generate.externals flag (formerly named kotlin.js.experimental.generateKotlinExternals while it was still experimental) in your gradle.properties file to set the generator’s behavior for all npm dependencies simultaneously. As usual, individual explicit settings take precedence over this general flag.

Manually generating external declarations via Gradle task

If you want to have full control over the declarations generated by Dukat, if you want to apply manual adjustments, or if you’re running into trouble with the auto-generated externals, you can also trigger the creation of the declarations for all your npm dependencies manually using the generateExternals Gradle task. This will generate declarations in a directory titled externals in your project root. Here, you can review the generated code and copy any parts you would like to use to your source directories. (Please be advised that manually providing external declarations in your source folder and enabling the generation of external declarations at build time for the same dependency can result in resolution issues.)

Migration preparation for kotlin.dom and kotlin.browser to separate artifacts

In order to evolve our browser and DOM bindings for Kotlin/JS faster and decouple them from the release cycle of the language itself, we are deprecating the current APIs located in the kotlin.dom and kotlin.browser packages. We provide replacements for these APIs in the kotlinx.dom and kotlinx.browser packages, which will be extracted to separate artifacts in a future release. Migrating to these new APIs is straightforward. Simply adjust the imports used in your project to point to these new kotlinx packages. Quick-fixes in IntelliJ IDEA, accessible via Alt-Enter, can help with this migration.

Preview: kotlinx-nodejs

We are excited to share a preview of our official bindings for the Node.js APIskotlinx-nodejs. While it has been possible to target Node.js with Kotlin for a long time, the full potential of the target is unlocked when you have typesafe access to its API. You can check out the kotlinx-nodejs bindings on GitHub.

To add kotlinx-nodejs to your project, make sure jcenter() is added to your repositories. You can then simply add a dependency on the artifact:

dependencies {
    // . . .
    implementation("org.jetbrains.kotlinx:kotlinx-nodejs:0.0.4")
}

After loading the Gradle changes, you can then experiment with the API provided by Node.js, for example by making use of their DNS resolution package:

fun main() {
    dns.lookup("example.org") { err, address, family ->
        console.log("address: $address, family IPv$family")
    }
}

Especially because this is still a preview version, we encourage you to give kotlinx-nodejs a try and report any issues you encounter in the repository’s issue tracker.

Deprecation of kotlin2js and kotlin-dce-js Gradle plugins

Starting with Kotlin 1.4, the old Gradle plugins for targeting JavaScript with Kotlin (kotlin2js and kotlin-dce-js) will be officially deprecated in favor of the kotlin.js Gradle plugin.
Key functionality that was available in these plugins, alongside the kotlin-frontend-plugin (which was already deprecated previously) has been condensed into the new plugin, allowing you to configure your Kotlin/JS target using a unified DSL that is also compatible with Kotlin/Multiplatform projects.

Since Kotlin 1.3.70, dead code elimination (DCE) has been applied automatically when using the browserProductionRun and browserProductionWebpack tasks, which run and create optimized bundles of your program. (Please note that dead code elimination is currently only available when targeting the browser for production output, not for Node.js or tests. But if you have additional use cases you’d like to see addressed, feel free to share them with us on YouTrack)

Additional quality-of-life improvements and notable fixes

  • We have added more compiler errors for prohibited usages of the @JsExport annotation to highlight such problems.
  • When using the IR compiler backend, we have enabled a new strategy that includes incremental compilation for klibs, which is one of many steps we are taking to improve compilation time.
  • The configuration for the webpack development server has been adjusted, preventing errors like ENOENT: no such file or directory when using the hot reload functionality.

Evolving the Kotlin Standard Library API

Kotlin 1.4 is a feature release in terms of Kotlin’s evolution, so it brings a lot of new features that you already know about from previous blog posts. However, another important aspect of a feature release is that it includes significant evolutionary changes in the existing API. Here’s a brief overview of the changes you can expect with the 1.4 release.

Stabilization of the experimental API

In order to ship the new things you want to see in Kotlin libraries as fast as possible, we provide experimental versions of them. This status indicates that work on the API is still in progress and that it could be changed incompatibly in the future. When you try to use the experimental API, the compiler warns you about its status and requires an opt-in (@OptIn annotation).

In feature releases, experimental APIs can be promoted to stable. At this point, we guarantee that their form and behavior won’t change suddenly (changes are only possible with a proper deprecation cycle). Once an API is officially stable, you can use the API safely without warnings or opt-ins.

With 1.4, we are promoting a number of experimental functions in the Kotlin libraries to stable. Here are some examples, along with versions in which they were introduced:

More API functions and classes are becoming stable in 1.4. Starting from this version (1.4.0-RC), using them in your project won’t require the @OptIn annotations.

Deprecation cycles

Feature releases also involve taking the next steps in existing deprecation cycles. While in incremental releases we only start new deprecation cycles with the WARNING level, in feature releases we tighten them to ERROR. In turn, API elements that already have the ERROR level can be completely hidden from new uses in code and only remain in binary form to preserve compatibility for already compiled code. Together, these steps ensure the gradual removal of deprecated API elements.

If your code uses API elements with a deprecation level of WARNING, the compiler warns you about such usages. When you update to Kotlin 1.4.0-RC, some of these warnings will turn into errors. Use the IDE prompts to properly replace erroneous usages with the provided alternatives and make sure that your code compiles again.

Detailed information about breaking changes in the Kotlin Standard Library API can be found in the Compatibility Guide for Kotlin 1.4.

Scripting

We skipped this section in a couple of previous blog posts, but we haven’t stopped working on Kotlin scripting to make it more stable, faster, and easier to use in 1.4. In the RC version, you can already observe better performance along with numerous fixes and functional improvements.

Artifacts renaming

In order to avoid confusion about artifact names, we’ve renamed kotlin-scripting-jsr223-embeddable and kotlin-scripting-jvm-host-embeddable to just kotlin-scripting-jsr223 and kotlin-scripting-jvm-host (without -embeddable). These artifacts depend on the kotlin-compiler-embeddable artifact, which shades the bundled third-party libraries to avoid usage conflicts. With this renaming, we’re making the usage of kotlin-compiler-embeddable (which is safer in general) the default for scripting artifacts.
If, for some reason, you need artifacts that depend on the unshaded kotlin-compiler, use the artifact versions with the -unshaded suffix, such as kotlin-scripting-jsr223-unshaded. Note that this renaming affects only the scripting artifacts that are supposed to be used directly; names of other artifacts remain unchanged.

CLion IDE plugin is now deprecated

We’ve launched a deprecation cycle for the CLion IDE plugin. Originally it was intended to be used to debug Kotlin/Native executables. Now this capability is available in IntelliJ IDEA Ultimate. We’ll stop publishing the CLion IDE plugin after the 1.4 release. Please contact us if this deprecation causes any problems. We will do our best to help you to solve them.

Compatibility

As in all major releases, some deprecation cycles of previously announced changes are coming to an end with Kotlin 1.4. All of these cases were carefully reviewed by the language committee and are listed in the Compatibility Guide for Kotlin 1.4. You can also explore these changes on YouTrack.

Release candidate notes

Now that we’ve reached the final release candidate for Kotlin 1.4, it is time for you to start compiling and publishing! Unlike previous milestone releases, binaries created with Kotlin 1.4.0-RC are guaranteed to be compatible with Kotlin 1.4.0.

How to try the latest features

As always, you can try Kotlin online at play.kotl.in.

In IntelliJ IDEA and Android Studio, you can update the Kotlin Plugin to version 1.4.0-RC. See how to do this.

If you want to work on existing projects that were created before installing the preview version, you need to configure your build for the preview version in Gradle or Maven. Note that unlike the previous preview versions, Kotlin 1.4.0-RC is also available directly from Maven Central. This means you won’t have to manually add the kotlin-eap repository to your build files.

You can download the command-line compiler from the GitHub release page.

You can use the following versions of the libraries published together with this release:

The release details and the list of compatible libraries are also available here.

Share your feedback


We’ll be very thankful if you find and report bugs to our issue tracker. We’ll try to fix all the important issues before the final release, which means you won’t need to wait until the next Kotlin release for your issues to be addressed.

You are also welcome to join the #eap channel in Kotlin Slack (get an invite here). In this channel, you can ask questions, participate in discussions, and get notifications about new preview builds.

Let’s Kotlin!

External contributions


We’d like to thank all of our external contributors whose pull requests were included in this release:

Continue ReadingKotlin 1.4.0-RC Released

Kotlin 1.4-M3: Generating Default Methods in Interfaces

In Kotlin 1.4, we’re adding new experimental ways for generating default methods in interfaces in the bytecode for the Java 8 target. Later, we’re going to be deprecating the @JvmDefault annotation in favor of generating all the method bodies in interfaces directly when the code is compiled in a special mode. Read more details of how it currently works and what will change, below.

In Kotlin, you can define methods with bodies in interfaces. It works if your code runs on Java 6 or 7, even before support for the default methods appeared on the JVM.

interface Alien {
   fun speak() = "Wubba lubba dub dub"
}

class BirdPerson : Alien

To make it work for older Java versions, the Kotlin compiler generates an additional class that contains an implementation of a default method as a static member. This is what the generated code looks like under the hood, at the bytecode level:

public interface Alien {
  String speak();

  public static final class DefaultImpls {
     public static String speak(Alien obj) {
        return "Wubba lubba dub dub";
     }
  }
}
public final class BirdPerson implements Alien {
  public String speak() {
    return Alien.DefaultImpls.speak(this);
  }
}

The Kotlin compiler generates the DefaultImpls class with the speak method. This method contains the default implementation. It takes an instance of an interface as a parameter and interprets it as this (in case you call other members of this interface inside). The class BirdPerson implementing the interface contains the same method, which only delegates to the implementation in DefaultImpls passing an actual this as an argument.

In Kotlin 1.2, we added experimental support for @JvmDefault annotation that works if your code targets Java 8. You can annotate each interface method having default implementation with @JvmDefault in order to get the default implementation generated in the bytecode:

interface Alien {
   @JvmDefault
   fun speak() = "Wubba lubba dub dub"
}

class BirdPerson : Alien

That only works in a special compiler mode: you can only use it when you specify the -Xjvm-default compiler argument.

The @JvmDefault annotation is going to be deprecated later. There’s no need to annotate each member with it; most probably you had to annotate all the interface methods with bodies, and it was quite verbose.

Eventually, we want to generate method bodies in interfaces by default when your code targets Java 8 or higher. It’s not easy to quickly make this change: we want to make sure you don’t have problems when you mix the libraries or modules of your application that are compiled with different Kotlin versions and different modes. The Kotlin compiler for future versions will continue to “understand” the old scheme of default methods, but we’ll slowly migrate to the new scheme.

New modes for generating default methods in interfaces

If your code targets Java 8 and you want to generate default methods in interfaces, you can use one of two new modes in Kotlin 1.4: -Xjvm-default=all or -Xjvm-default=all-compatibility.

In all mode, you only have default methods generated by the compiler, no more DefaultImpls objects, and no need to additionally annotate separate methods. This is the generated code for our initial sample:

// -Xjvm-default=all
public interface Alien {
  default String speak() {
     return "Wubba lubba dub dub";
 }
}
public final class BirdPerson implements Alien {}

Note that class BirdPerson implementing the interface doesn’t contain the speak method: it automatically reuses the “super” implementation thanks to the JVM support.

The Kotlin compiler of the newer versions will “understand” the old scheme. If your class compiled with the new scheme implements an interface compiled with the old scheme (with DefaultImpls), the compiler will recognize this and generate a hidden method in the class that delegates to the corresponding DefaultImpls method, as before.

The only problem that may arise is if you recompile your old code with the default method implementation and some other code depends on it, which you don’t recompile. In this case, use the all-compatibility mode. Then both default method bodies and DefaultImpls classes are generated:

// -Xjvm-default=all-compatibility
public interface Alien {
  default String speak() {
     return "Wubba lubba dub dub";
  }

  public static final class DefaultImpls {
     public static String speak(Alien obj) {
        // Calling the default method from the interface:
        return obj.$default$speak();
     }
  }
}
public final class BirdPerson implements Alien {}

Inside DefaultImpls the Kotlin compiler calls specifically the default method defined in the interface. (To make it a non-virtual call, the compiler makes a special trick: it generates an additional synthetic method inside an interface and calls it instead.)

With all-compatibility mode you don’t need to recompile the classes that already use your interface; they continue to work correctly:

public final class Moopian implements Alien {
  public String speak() {
    return Alien.DefaultImpls.speak(this);
  }
}

all-compatibility mode guarantees binary compatibility for Kotlin clients but generates more methods and classes in the bytecode.

Fixing an issue with delegates

Before, it was a bit confusing to use an interface with @JvmDefault methods together with the “implementation by delegation” feature. If you used an interface with @JvmDefault as a delegate, the default method implementations were called even if the actual delegate type provided its own implementation:

interface Producer {
   fun produce() = "in interface"
}

class ProducerImpl : Producer {
   override fun produce() = "in class"
}

class DelegatedProducer(val p: Producer) : Producer by p

fun main() {
   val prod = ProducerImpl()
   // prints "in interface" if 'produce()' is annotated with @JvmDefault
   // prints "in class" in new jvm-default modes
   println(DelegatedProducer(prod).produce())
}

With the new jvm-default modes, it works as you would expect: the overridden version of produce is called when you delegate your implementation to the ProducerImpl class.

@JvmDefaultWithoutCompatibility

If you compile your code with all-compatibility mode and add a new interface, you can annotate it with the @JvmDefaultWithoutCompatibility annotation. It turns on “no compatibility mode” (-Xjvm-default=all) for this specific class. This way, no DefaultImpls objects will be generated. Since you’ve just added a new interface, there’s no code that calls it via the old scheme, and nothing can break.

To be precise, in all-compatibility mode you can use @JvmDefaultWithoutCompatibility to annotate all interfaces which aren’t a part of the public API (more correct is to consider public binary interface, and to say ABI), and therefore aren’t used by the existing clients.

More about all-compatibility mode for library authors

The all-compatibility mode is designed specifically for library authors to allow them to switch to the new scheme gradually and guarantee the binary compatibility for the library. And so, the following details and compatibility issues are aimed mainly at library authors.

Guaranteeing the binary compatibility between the new and old schemes is not totally “seamless”.
To prevent compatibility issues that might arise, the compiler reports an error in specific corner cases, while the @JvmDefaultWithoutCompatibility annotation suppresses this error. The following section describes the reasons for it and the use cases.

Consider a class that inherits from a generic interface:

interface LibGeneric<T> {
   fun foo(p: T): T = p
}

open class LibString : LibGeneric<String>

In -Xjvm-default=all-compatibility mode, the Kotlin compiler generates an error. Let’s first see why and then discuss how you can fix it.

Under the hood, to make such code work with DefaultImpls scheme, the Kotlin compiler of the previous version (or without using any -Xjvm-default flags) generates an additional method with the specialized signature in the class:

open class LibString {
   // Generated implicitly:
   fun foo(String): String { ... }
}

Sometimes, this specialized method is called in the generated bytecode. In pure Kotlin, it happens only in rare cases when your LibString class is open and you call foo from a subclass of LibString via super.foo(). In mixed projects, if you use this code from Java, the specialized version gets called every time you call foo on a LibString instance!

Without such override, you could easily break the binary compatibility: if you recompiled your LibString class with the new all-compatibility mode, and run it against the old binaries, you could get a NoSuchMethodError error!

The goal of all-compatibility mode is to guarantee binary compatibility at least for the Kotlin clients. That’s why having unexpected NoSuchMethodError errors is unacceptable. In order to prevent this, the Kotlin compiler could potentially generate the same hidden specialized method as before, however, it would cause problems when updating from all-compatibility to all mode, and it would also have issues with using default methods in diamond hierarchies. Generating such auxiliary implicit methods was necessary with the DefaultImpls scheme but is not needed when default methods are supported on the JVM level and can cause more confusion (for more details see Appendix: why we don’t like implicit methods).

We decided to prevent this binary compatibility problem by making your choice explicit.

Fixing the compiler error

One option you have is to provide an explicit override:

interface LibGeneric<T> {
   fun foo(p: T): T = p
}

open class LibString : LibGeneric<String> {
   override fun foo(p: String): String = super.foo(p)
}

Yes, it’s a bit of verbosity but for a good reason! If this code can be used from subclasses in Kotlin or from Java, adding explicit override guarantees that the older binaries will continue to work with new versions of your library compiled in all-compatibility mode.

Another option is to annotate your class with the @JvmDefaultWithoutCompatibility annotation. It turns on “no compatibility mode” for this specific class. Then an explicit override method is not required and no implicit methods are generated:

interface LibGeneric<T> {
   fun foo(p: T): T = p
}

@JvmDefaultWithoutCompatibility
open class LibString : LibGeneric<String> {
    // no implicit member
}

Appendix: Why we don’t like implicit methods

Why don’t we generate hidden methods like in the old scheme? Consider the following diagram which represents a diamond hierarchy – the Java class JavaClass implements the Kotlin Base interface both through extending KotlinClass and implementing Derived interface:

Let’s imagine that Kotlin continues to generate implicit overrides (as was necessary before with the DefaultImpls scheme). Then the code JavaClass().foo() prints 0 and not 42! That becomes a new puzzler: there are only two methods (returning 0 and returning 42) and it’s really confusing why the method from the base class is called and not the more specific one from Derived. When you take into consideration an implicit method from KotlinClass, the result makes sense. But we really want to avoid such puzzlers by not generating the implicit methods in the first place – and rather force developers to provide explicit methods when it’s necessary for compatibility reasons.

Conclusion

If you used the @JvmDefault annotation before, you can safely remove it and use one of the new modes. If you already used -Xjvm-default=enable, which generated only the default method implementations, you can now replace it with -Xjvm-default=all.

So far this support remains experimental but we’re going to switch the default mode continuously first to all-compatibility and then to all in the future major Kotlin versions. If no -Xjvm-default is specified now, the generated code will continue to use DefaultImpls.

How to try it

You can already try these new modes with Kotlin 1.4-M3 version. See here how to update the Kotlin Plugin to it.

Share your feedback

We’re grateful for all your bug reports in our issue tracker, and we’ll do our best to fix all the most important issues before the final release.

You are also welcome to join the #eap channel in our Kotlin Slack (get an invite here). In this channel, you can ask questions, participate in discussions, and get notifications of new preview builds.

Let’s Kotlin!

Continue ReadingKotlin 1.4-M3: Generating Default Methods in Interfaces

End of content

No more pages to load