Auto Added by WPeMatico

Kotlin 1.5.20 Released!

Kotlin continues to stay up to date with latest Java features such as dynamic invocations and to provide better interoperability with Java by adding support for Java’s Lombok and JSpecify. We are also continuing our work of making the standard library consistent across platforms, as well as investing in Gradle tooling and the new JS IR backend.

Update to Kotlin 1.5.20

This blog post provides an overview of the updates in this release:

Auto-update to Kotlin 1.5.20

If you use IntelliJ IDEA or Android Studio, your IDE will give you the option to automatically update to the new Kotlin release as soon as it becomes available.

Learn more about installing Kotlin 1.5.20.

Kotlin/JVM

To benefit from the latest JVM features, Kotlin has extended the use of dynamic invocations (invokedynamic). Kotlin 1.5.0 brought default support for compilation of SAM adapters, while keeping similar features for string concatenation and lambdas Experimental. Kotlin 1.5.20 makes compilation string concatenation to dynamic invocations the default as well.

To maintain the best interoperability with Java, Kotlin 1.5.20 brings experimental support for:

  • Calling Java’s Lombok-generated methods within the same module. The experimental Lombok compiler plugin allows using Java’s Lombok-generated declarations in mixed Kotlin/Java sources. Lombok annotations work only in Java sources and are ignored if you use them in Kotlin code.
    Supported annotations include @With, @Data, @Getter, @Setter, @NoArgsConstructor, @RequiredArgsConstructor, and @AllArgsConstructor.
  • JSpecify project, which includes a standard unified set of Java nullness annotations. This allows you to provide more detailed nullability information to help Kotlin maintain null safety when interoperating with Java. You can set default nullability for the declaration, package, or module scope, specify parametric nullability, and more. 
    Please note that the JSpecify project is under active development. Its API and implementation can change significantly at any time.

Here is an example of how Kotlin can handle JSpecify annotations:

// JavaClass.java
import org.jspecify.nullness.*;

@NullMarked
public class JavaClass {
    public String notNullableString() { return ""; }
    public @Nullable String nullableString() { return ""; }
}
// Test.kt
fun kotlinFun() = with(JavaClass()) {
  notNullableString().length // OK
  nullableString().length    // Warning: receiver nullability mismatch
}

Kotlin/Native

The Kotlin/Native compiler can now export documentation comments (KDoc) from Kotlin code to Objective-C frameworks. This will make these comments visible to the framework’s consumers. This support also works for Swift, and it is Experimental

Another improvement concerns the Array.copyInto() operation inside one array. It now works up to 20 times faster (depending on the number of objects being copied) due to memory management optimization for this case.

Kotlin/JS

Kotlin 1.5.0 has already delivered the new Stable JVM IR backend, so the only missing piece of the new Kotlin IR backend is the Stable JS part. We’re continuing our work to make the Kotlin/JS IR backend Stable, and your feedback would really help us.

An easy way to migrate to the new JS backend is to follow our new migration guide. The guide describes the changes you’ll need to make in your Kotlin/JS code to make it work with the new IR compiler. If you encounter any issues, please report them to our issue tracker, YouTrack.

Gradle

Kotlin 1.5.20 delivers a couple of tooling improvements:

Standard library

Kotlin 1.5.20 continues to provide a similar experience on all platforms for standard library Char features:

  • isLowerCase()/isUpperCase() now provides the same result on all platforms by checking all characters, not only letters.
  • digitToInt() now supports all Unicode digit characters for all platforms – Kotlin/JVM, Kotlin/Native, and Kotlin/JS. Previously, it provided full support only for Kotlin/JVM.

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.

How to install Kotlin 1.5.20

If you already use IntelliJ IDEA or Android Studio, your IDE will suggest updating Kotlin to 1.5.20 automatically. You can also update it manually by following these instructions

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

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

Make sure that you have also updated the kotlinx libraries to compatible versions and specified version 1.5.20 of Kotlin in the build scripts of your existing projects.

If you need the command-line compiler, download it from the Github release page.

If you run into any problems

Read and watch more

External contributors 👏👏👏

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

Alexey Stepanov, Jinseong Jeon, Tianyu Geng, Mark Punzalan, pyos, Mike Sinkovsky, Aleksey Kladov, Mads Sig Ager, Steven Schäfer, Ting-Yuan Huang, Victor Turansky, scaventz, Stefan M, Carlos Ballesteros Velasco, StefMa, Mattia Iavarone, Florian Kistner, Julius Kunze, Sergey Rubanov, Matthew Gharrity, enbandari, Campbell Jones, Br0mm, Kevin Galligan, yantimirov-timur, Ben Asher, Julia, Jared Woolston, Federico Tomassetti, Jens Klingenberg, Nicola Corti, vldf, Dominic Fischer, Martin Petrov, Renee Vandervelde, Robert Hencke, Rodrigo B. de Oliveira, Jeffrey McNally-Dawes, Scott Pierce, Sebsatian Keller, James Wald, Hyojae Kim, hungvietnguyen, Him188, Henrik Tunedal, AJ Alt, Giuseppe Barbieri, Francis Lavoie, Dico Karssiens, Dave Leeds, Thiago Henrique Hüpner, Thomas Vos, Daniel, Collin Monahan, Toshiaki Kameyama, Tristan Greeno, Vanessa Pyne, Charlie Jiang, Cedric Champeau, Boris Pristupa, Bingran, youta ogino, Aydar Mukhametzyanov, Ying Li, Zac Sweers, zadorotskas, ebukreev, kdnakt, 0xflotus, Abhishek Sudhakaran, Marcin Aman, Marcin Kraszewski, Matt Chowning, luca992, Lucas Diego, Louis CAD, Michael Blackman, Michael Hoisie, Lidonis Calhau, LanderlYoung, Kyle Kauffman, Miquel Beltran, Mohit Jayanti Gurumukhani, Muhammad Hakim Asy’ari, Márton Braun, Nekoyue, Nick Apperley, toxicbakery, KotlinIsland, Kjell Winblad, Kevin Waldock, Nils Kunze, Noah, Nwokocha wisdom maduabuchi, Paul Idstein, Keegan Witt, Jonas Seibert, Jiaming Lu


Update to Kotlin 1.5.20

Continue ReadingKotlin 1.5.20 Released!

Kotlin 1.5.0 – the First Big Release of 2021

Welcome the first feature release in accordance with the new release scheduleKotlin 1.5.0!

This release delivers stable language features such as JVM records, sealed interfaces, inline classes, and includes the new default JVM IR compiler. Your feedback on the feature previews in Kotlin 1.4.30 and Kotlin 1.5.0 EAP releases have really helped us to stabilize these features.
We’re very grateful for your assistance! Thank you!

More than 25,000 developers have already tried the new JVM IR compiler in IntelliJ IDEA.

You will notice the benefits over time. The new compiler shares a unified pipeline and business logic with Kotlin/Native and Kotlin/JS IR compilers, which will allow us to implement most features, optimizations, and bug fixes for all platforms simultaneously. It will also allow you to add custom processing and transformations that will automatically work on all platforms.

Do you have questions about Kotlin 1.5.0? Roman Elizarov, Svetlana Isakova, and other members of the Kotlin team will be available to answer your questions live on May 25 during the Kotlin 1.5 Online Event.

Register for the Kotlin 1.5 Online Event


In this blog post, you will find an overview of:

Auto-update to Kotlin 1.5.0

If you are using IntelliJ IDEA or Android Studio, it will give you the option to automatically update to the new Kotlin release as soon as it becomes available.

Learn more about installing Kotlin 1.5.0.

Stable language features

Kotlin 1.5.0 includes stable versions of the new language features presented for preview in 1.4.30:

  • Support for JVM records to remain interoperable with the latest Java features – record classes.
    To use a Kotlin class as a record in Java code, make it a data class and mark it with the @JvmRecord annotation:

    @JvmRecord
    data class User(val name: String, val age: Int)
    

    Learn more about requirements for using JVM records.

  • Sealed interfaces. The sealed modifier works on interfaces the same way it works on classes – all implementations of a sealed interface are known at compile time.

    sealed interface Polygon
    
  • Sealed class improvements. Previously, all subclasses had to be in the same file with sealed classes. Now they can be in all files of the same compilation unit and the same package.
  • Inline classes are a subset of value-based classes that only hold values. You can use them as wrappers for a value of a certain type without the additional overhead that comes from using memory allocations. Use the value modifier for the declaration.

    @JvmInline //required for the JVM backend
    value class Password(val s: String)
    

Learn more about Kotlin 1.5.0 language features

Standard and test library improvements

The New stable APIs for unsigned integer types are the most anticipated Kotlin 1.5.0 library improvements based on the survey we conducted in the Kotlin 1.5.0-RC blog post.

The standard library provides many helpful features, including:

  • The new stable APIs for unsigned integer types as well as for ranges, progressions, and functions for them. Learn more about unsigned integers.
  • Extension functions for java.nio.file.Path to use the modern non-blocking Java IO in a Kotlin-idiomatic style.
  • String and Char API improvements including the new locale-agnostic API for changing the case of strings and characters, a set of new functions for conversion between characters and their integer codes and numeric values, and multiplatform support for more char functions.
  • Duration API changes including using a Long value for the internal representation and providing new properties for retrieving a duration as a Long value.

The test library comes with a set of important improvements:

  • Single kotlin-test dependency in the common source set of multiplatform projects.
  • Automatic choice of a testing framework for Kotlin/JVM source sets when you specify only the kotlin-test dependency.
  • A number of assertion function updates.

Learn more about library improvements

Kotlin/JVM

Kotlin 1.5.0 brings:

Kotlin/Native

Kotlin 1.5.0 provides:

  • Support for compiler caches in debug mode for linuxX64 and iosArm64 targets. With compiler caches enabled, most debug compilations complete much faster, except for the first one. Measurements showed about a 200% speed increase on our test projects.
  • Deactivation of the built-in memory leak checker to avoid issues that may cause application crashes. Learn how to activate the memory leak checker if you need it.

Kotlin/JS

Kotlin/JS moves towards promoting the new Koltin/JS IR compiler to Beta. Many well-known frameworks and libraries are already available for the IR compiler: KVision, fritz2, doodle, and others.

If you’re a library author, you can add your library to these by migrating your library using the backwards compatibility.

Another additional improvement is building JS bundles using webpack 5 instead of webpack 4.

How to install Kotlin 1.5.0

If you already use IntelliJ IDEA or Android Studio, it will suggest updating Kotlin to 1.5.0 automatically once the release is out. You can also update it manually by following these instructions. Note that only Android Studio 4.2.0, Arctic Fox Canary 15, and later versions support Kotlin 1.5.0.

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

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

Make sure that you have also updated the kotlinx libraries to compatible versions and specified the Kotlin version 1.5.0 in the build scripts of your existing projects.

If you need the command-line compiler, download it from the Github release page.

If you run into any problems

Kotlin 1.5 Online Event

Join the Kotlin 1.5 Online Event on May 25, where the Kotlin team will answer all your questions about the latest release. You can ask about anything you’d like to know, or if you don’t have any questions and are just interested in the answers, that is great too. The event will last for 1.5 hours.

Post your questions on Twitter with #kotlin15ask or add your questions in the registration form.

Register for the Kotlin 1.5 Online Event

We will also conduct an Ask Me Anything (AMA) session on Reddit on May 27-28 to address any questions left unanswered as well as answer any new ones too.

Compatibility

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

Watch and read more

Watch Kotlin YouTube:

Read the Kotlin blog:

Learn more from the Kotlin docs:

External contributors

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

Jinseong Jeon, Mads Ager, Ivan Gavrilovic, pyos, Steven Schäfer, Iaroslav Postovalov, scaventz, Kristoffer Andersen, Bingran, Stefan Wolf, Victor Turansky, fjjohnchen, justin.wei, Nelson Osacky, Mikhail Galanin, Michael Hoisie, Kris Hall, Kevin Bierhoff, Jiaxiang Chen, Hung Nguyen, Cedric Champeau.

Top issue reporters from YouTrack

We’d like to thank 👏👏👏 all the members of the community who have helped us make this release better by reporting issues to YouTrack! We’ve made a list of the top 20 reporters and would like to thank them specifically:

Morgan Bartholomew (118 issues); Marc Knaup (78 issues); Ryan Nett (61 issues); Louis CAD (48 issues); Daniil Stepanov (44 issues); AndroidDeveloperLB (39 issues); Victor Turansky (38 issues); Jinseong Jeon (35 issues); Zac Sweers (25 issues); Łukasz Wasylkowski (22 issues); Tianyi Guan (21 issues); Christoph Sturm (20 issues); Axel Fontaine (19 issues); Alexander Nozik (18 issues); Robert Stoll (18 issues); Björn Kautler (18 issues); Róbert Papp (14 issues); Andreas Malik (14 issues); Lorenzo Neumann (14 issues);
Iaroslav Postovalov (14 issues).


Install Kotlin 1.5.0 and register for the Kotlin 1.5 Online Event!

Continue ReadingKotlin 1.5.0 – the First Big Release of 2021

Kotlin 1.5.0-RC Released: Changes to the Standard and Test Libraries

Kotlin 1.5.0-RC is available with all the features planned for 1.5.0 – check out the entire scope of the upcoming release! New language features, stdlib updates, an improved testing library, and many more changes are receiving a final polish. The only additional changes before the release will be fixes.

Try the modern Kotlin APIs on your real-life projects with 1.5.0-RC and help us make the release version better! Report any issues you find to our issue tracker, YouTrack.

Install 1.5.0-RC

In this post, we’ll walk you through the changes to the Kotlin standard and test libraries in 1.5.0-RC:

You can find all the details below!

Stable unsigned integer types

The standard library includes the unsigned integer API that comes in useful for dealing with non-negative integer operations. It includes:

  • Unsigned number types: UInt, ULong, UByte, UShort, and related functions, such as conversions.
  • Aggregate types: arrays, ranges, and progressions of unsigned integers: UIntArray, UIntRange, and similar containers for other types.

Unsigned integer types have been available in Beta since Kotlin 1.3. Now we are classifying the unsigned integer types and operations as stable, making them available without opt-in and safe to use in real-life projects.

Namely, the new stable APIs are:

  • Unsigned integer types
  • Ranges and progressions of unsigned integer types
  • Functions that operate with unsigned integer types
fun main() {
//sampleStart
    val zero = 0U // Define unsigned numbers with literal suffixes
    val ten = 10.toUInt() // or by converting non-negative signed numbers
    //val minusOne: UInt = -1U // Error: unary minus is not defined
    val range: UIntRange = zero..ten // Separate types for ranges and progressions

    for (i in range) print(i)
    println()
    println("UInt covers the range from ${UInt.MIN_VALUE} to ${UInt.MAX_VALUE}") // UInt covers the range from 0 to 4294967295
//sampleEnd
}

Arrays of unsigned integers remain in Beta. So do unsigned integer varargs that are backed by arrays. If you want to use them in your code, you can opt-in with the @ExperimentalUnsignedTypes annotation.

Learn more about unsigned integers in Kotlin.

Extensions for java.nio.file.Path API

Kotlin now provides a way to use the modern non-blocking Java IO in a Kotlin-idiomatic style out of the box via the extension functions for java.nio.file.Path.

Here is a small example:

import kotlin.io.path.*
import java.nio.file.Path

fun main() {
    // construct path with the div (/) operator
    val baseDir = Path("/base")
    val subDir = baseDir / "subdirectory"

    // list files in a directory
    val kotlinFiles = Path("/home/user").listDirectoryEntries("*.kt")
    // count lines in all kotlin files
    val totalLines = kotlinFiles.sumOf { file -> file.useLines { lines -> lines.count() } }
}

These extensions were introduced as an experimental feature in Kotlin 1.4.20, and are now available without an opt-in. Check out the kotlin.io.path package for the list of functions that you can use.

The existing extensions for File API remain available, so you are free to choose the API you like best.

Locale-agnostic API for uppercase and lowercase

Many of you are familiar with the stdlib functions for changing the case of strings and characters: toUpperCase(), toLowerCase(), toTitleCase(). They generally work fine, but they can cause a headache when it comes to dealing with different platform locales – they are all locale-sensitive, which means their result can differ depending on the locale. For example, what does ”Kotlin”.toUpperCase() return? “Obviously KOTLIN”, you would say. But in the Turkish locale, the capital i is İ, so the result is different: KOTLİN.

Now there is a new locale-agnostic API for changing the case of strings and characters: uppercase(), lowercase(), titlecase() extensions, and their *Char() counterparts. You may have already tried its preview in 1.4.30.

The new functions work the same way regardless of the platform locale settings. Just call these functions and leave the rest to the stdlib.

The new functions work the same way regardless of the platform locale settings. Just call these functions and leave the rest to the stdlib.

fun main() {
//sampleStart
    // replace the old API
    println("Kotlin".toUpperCase()) // KOTLIN or KOTLİN or?..

    // with the new API
    println("Kotlin".uppercase()) // Always KOTLIN
//sampleEnd
}

On the JVM, you can perform locale-sensitive case change by calling the new functions with the current locale as an argument:

"Kotlin".uppercase(Locale.getDefault()) // Locale-sensitive uppercasing

The new functions will completely replace the old ones, which we’re deprecating now.

Clear Char-to-code and Char-to-digit conversions

The operation for getting a UTF-16 code of a character – the toInt() function – was a common pitfall because it looks pretty similar to String.toInt() on one-digit strings that produces an Int presented by this digit.

"4".toInt() // returns 4
'4'.toInt() // returns 52

Additionally, there was no common function that would return the numeric value 4 for Char '4'.

To solve these issues, there is now a set of new functions for conversion between characters and their integer codes and numeric values:

  • Char(code) and Char.code convert between a char and its code.
  • Char.digitToInt(radix: Int) and its *OrNull version create an integer from a digit in the specified radix.
  • Int.digitToChar(radix: Int) creates a char from a digit that represents an integer in the specified radix.

These functions have clear names and make the code more readable:

fun main() {
//sampleStart
    val capsK = Char(75) // ‘K’
    val one = '1'.digitToInt(10) // 1
    val digitC = 12.digitToChar(16) // hexadecimal digit ‘C’

    println("${capsK}otlin ${one}.5.0-R${digitC}") // “Kotlin 1.5.0-RC”
    println(capsK.code) // 75
//sampleEnd
}

The new functions have been available since Kotlin 1.4.30 in the preview mode and are now stable. The old functions for char-to-number conversion (Char.toInt() and similar functions for other numeric types) and number-to-char conversion (Long.toChar() and similar except for Int.toChar()) are now deprecated.

Extended multiplatform char API

We’re continuing to extend the multiplatform part of the standard library to provide all of its capabilities to the multiplatform project common code.

Now we’ve made a number of Char functions available on all platforms and in common code. These functions are:

  • Char.isDigit(), Char.isLetter(), Char.isLetterOrDigit() that check if a char is a letter or a digit.
  • Char.isLowerCase(), Char.isUpperCase(), Char.isTitleCase() that check the case of a char.
  • Char.isDefined() that checks whether a char has a Unicode general category other than Cn (undefined).
  • Char.isISOControl() that checks whether a char is an ISO control character, that has a code in the ranges u0000..u001F or u007F..u009F.

The property Char.category and its return type enum class CharCategory, which indicates a character’s general category according to Unicode, are now available in multiplatform projects.

fun main() {
//sampleStart
    val array = "Kotlin 1.5.0-RC".toCharArray()
    val (letterOrDigit, punctuation) = array.partition { it.isLetterOrDigit() }
    val (upperCase, notUpperCase ) = array.partition { it.isUpperCase() }

    println("$letterOrDigit, $punctuation") // [K, o, t, l, i, n, 1, 5, 0, R, C], [ , ., ., -]
    println("$upperCase, $notUpperCase") // [K, R, C], [o, t, l, i, n, , 1, ., 5, ., 0, -]

    if (array[0].isDefined()) println(array[0].category)
//sampleEnd
}

Strict versions of String?.toBoolean()

Kotlin’s String?.toBoolean() function is widely used for creating boolean values from strings. It works pretty simply: it’s true on a string “true” regardless of its case and false on all other strings, including null.

While this behavior seems natural, it can hide potentially erroneous situations. Whatever you convert with this function, you get a boolean even if the string has some unexpected value.

New case-sensitive strict versions of the String?.toBoolean() are here to help avoid such mistakes:

  • String.toBooleanStrict() throws an exception for all inputs except literals “true” and “false”.
  • String.toBooleanStrictOrNull() returns null for all inputs except literals “true” and “false”.
fun main() {
//sampleStart
    println("true".toBooleanStrict()) // True
    // println("1".toBooleanStrict()) // Exception
    println("1".toBooleanStrictOrNull()) // null
    println("True".toBooleanStrictOrNull()) // null: the function is case-sensitive
//sampleEnd
}

Duration API changes

The experimental duration and time measurement API has been available in the stdlib since version 1.3.50. It offers an API for the precise measurement of time intervals.

One of the key classes of this API is Duration. It represents the amount of time between two time instants. In 1.5.0, Duration receives significant changes both in the API and internal representation.

Duration now uses a Long value for the internal representation instead of Double. The range of Long values enables representing more than a hundred years with nanosecond precision or a hundred million years with millisecond precision. However, the previously supported sub-nanosecond durations are no longer available.

We are also introducing new properties for retrieving a duration as a Long value. They are available for various time units: Duration.inWholeMinutes, Duration.inWholeSeconds, and others. These functions come to replace the Double-based properties such as Duration.inMinutes.

Another change is a set of new factory functions for creating Duration instances from integer values. They are defined directly in the Duration type and replace the old extension properties of numeric types such as Int.seconds.

@ExperimentalTime
fun main() {
//sampleStart
    val duration = Duration.milliseconds(120000)
    println("There are ${duration.inWholeSeconds} seconds in ${duration.inWholeMinutes} minutes")
//sampleEnd
}

Given such major changes, the whole duration and time measurement API remains experimental in 1.5.0 and requires an opt-in with the @ExperimentalTime annotation.

Please try the new version and share your feedback in our issue tracker, YouTrack.

Math operations: floored division and the mod operator

In Kotlin, the division operator (/) on integers represents the truncated division, which drops the fractional part of the result. In modular arithmetics, there is also an alternative – floored division that rounds the result down (towards the lesser integer), which produces a different result on negative numbers.

Previously, floored division required a custom function like:

fun floorDivision(i: Int, j: Int): Int {
    var result = i / j
    if (i != 0 && result <= 0) result--
    return result
}

In 1.5.0-RC, we present the floorDiv() function that performs floored division on integers.

fun main() {
//sampleStart
    println("Truncated division -5/3: ${-5 / 3}")
    println("Floored division -5/3: ${-5.floorDiv(3)}")
//sampleEnd
}

In 1.5.0, we’re introducing the new mod() function. It now works exactly as its name suggests – it returns the modulus that is the remainder of the floored division.

It differs from Kotlin’s rem() (or % operator). Modulus is the difference between a and a.floorDiv(b) * b. Non-zero modulus always has the same sign as b while a % b can have a different one. This can be useful, for example, when implementing cyclic lists:

fun main() {
//sampleStart
    fun getNextIndexCyclic(current: Int, size: Int ) = (current + 1).mod(size)
    fun getPreviousIndexCyclic(current: Int, size: Int ) = (current - 1).mod(size)
    // unlike %, mod() produces the expected non-negative value even if (current - 1) is less than 0

    val size = 5
    for (i in 0..(size * 2)) print(getNextIndexCyclic(i, size))
    println()
    for (i in 0..(size * 2)) print(getPreviousIndexCyclic(i, size))
//sampleEnd
}

Collections: firstNotNullOf() and firstNotNullOfOrNull()

Kotlin collections API covers a range of popular operations on collections with built-in functions. For cases that aren’t common, you usually combine calls of these functions. It works, but this doesn’t always look very elegant and can cause overhead.

For example, to get the first non-null result of a selector function on the collection elements, you could call mapNotNull() and first(). In 1.5.0, you can do this in a single call of a new function firstNotNullOf(). Together with firstNotNullOf(), we’re adding its *orNull() counterpart that produces null if there is no value to return.

Here is an example of how it can shorten your code.

Assume that you have a class with a nullable property and you need its first non-null value from a list of the class instances.

class Item(val name: String?)

You can implement this by iterating the collection and checking if a property in not null:

// Option 1: manual implementation
for (element in collection) {
    val itemName = element.name
    if (itemName != null) return itemName
}
return null

Another way is to use the previously existing functions mapNotNull() and firstOrNull(). Note that mapNotNull() builds an intermediate collection, which requires additional memory, especially for big collections. And so, a transformation to a sequence may be also needed here.

// Option 2: old stdlib functions
return collection
    // .asSequence() // Avoid creating intermediate list for big collections
    .mapNotNull { it.name }
    .firstOrNull()

And this is how it looks with the new function:

// Option 3: new firstNotNullOfOrNull()
return collection.firstNotNullOfOrNull { it.name }

Test library changes

We haven’t shipped major updates to the Kotlin test library kotlin-test for several releases, but now we’re providing some long-awaited changes. With 1.5.0-RC, you can try a number of new features:

  • Single kotlin-test dependency in multiplatform projects.
  • Automatic choice of a testing framework for Kotlin/JVM source sets.
  • Assertion function updates.

kotlin-test dependency in multiplatform projects

We’re continuing our development of the configuration process for multiplatform projects. In 1.5.0, we’ve made it easier to set up a dependency on kotlin-test for all source sets.

Now the kotlin-test dependency in the common test source set is the only one you need to add. The Gradle plugin will infer the corresponding platform dependency for other source sets:

  • kotlin-test-junit for JVM source sets. You can also switch to kotlin-test-junit-5 or kotlin-test-testng if you enable them explicitly (read on to learn how).
  • kotlin-test-js for Kotlin/JS source sets.
  • kotlin-test-common and kotlin-test-annotations-common for common source sets.
  • No extra artifact for Kotlin/Native source sets because Kotlin/Native provides built-in implementations of the kotlin-test API.

Automatic choice of a testing framework for Kotlin/JVM source sets

Once you specify the kotlin-test dependency in the common test source set as described above, the JVM source sets automatically receive the dependency on JUnit 4. That’s it! You can write and run tests right away!

This is how it looks in the Groovy DSL:

kotlin {
    sourceSets {
        commonTest {
            dependencies {
                 // This brings the dependency
                // on JUnit 4 transitively
                implementation kotlin('test')
            }
        }
    }
}

And in the Kotlin DSL it is:

kotlin {
    sourceSets {
        val commonTest by getting {
            dependencies {
                // This brings the dependency
                // on JUnit 4 transitively
                implementation(kotlin("test"))
            }
        }
    }
}

You can also switch to JUnit 5 or TestNG by simply calling a function in the test task: useJUnitPlatform() or useTestNG().

kotlin {
    jvm {
        testRuns["test"].executionTask.configure {
            // enable TestNG support
            useTestNG()
            // or
            // enable JUnit Platform (a.k.a. JUnit 5) support
            useJUnitPlatform()
        }
    }
}

The same works in JVM-only projects when you add the kotlin-test dependency.

Assertion functions updates

For 1.5.0, we’ve prepared a number of new assertion functions along with improvements to existing ones.

First, let’s take a quick look at the new functions:

  • assertIs<T>() and assertIsNot<T>() check the value’s type.
  • assertContentEquals() compares the container content for arrays, sequences, and any Iterable. More precisely, it checks whether expected and actual contain the same elements in the same order.
  • assertEquals() and assertNotEquals() for Double and Float have new overloads with a third parameter – precision.
  • assertContains() checks the presence of an item in any object with the contains() operator defined: array, list, range, and so on.

Here is a brief example that shows the usage of these functions:

@Test
fun test() {
    val expectedArray = arrayOf(1, 2, 3)
    val actualArray = Array(3) { it + 1 }

    assertIs(actualArray[0])
    assertContentEquals(expectedArray, actualArray)
    assertContains(expectedArray, 2)

    val x = sin(PI)

    // precision parameter
    val tolerance = 0.000001

    assertEquals(0.0, x, tolerance)
}

Regarding the existing assertion functions – it’s now possible to call suspending functions inside the lambda passed to assertTrue(), assertFalse(), and expect() because these functions are now inline.

Try all the features of Kotlin 1.5.0

Bring all these modern Kotlin APIs to your real-life projects with 1.5.0-RC!

In IntelliJ IDEA or Android Studio, install the Kotlin plugin 1.5.0-RC. Learn how to get the EAP plugin versions.

Build your existing projects with 1.5.0-RC to check how they will work with 1.5.0. With the new simplified configuration for preview releases, you just need to change the Kotlin version to 1.5.0-RC and adjust the dependency versions, if necessary.

Install 1.5.0-RC

The latest version will be available online in the Kotlin Playground soon.

Compatibility

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

Release candidate notes

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

Share feedback

This is the final opportunity for you to affect the next feature release! Share any issues you find with us in the issue tracker. Make Kotlin 1.5.0 better for you and the community!

Install 1.5.0-RC

Continue ReadingKotlin 1.5.0-RC Released: Changes to the Standard and Test Libraries

Kotlin Plugin 2021.1 Released: Improved IDE Performance and Better Support for Refactorings

The newest release of IntelliJ IDEA, version 2021.1, comes with the improved Kotlin plugin. Enjoy an improved developer experience with faster code completion and highlighting, change signatures with better IDE support, benefit from better debugging experience for evaluating properties, and more.

Here is what you’ll get by installing the new plugin:

Auto-update to this new release

IntelliJ IDEA will give you the option to automatically update to the new release once it is out.

If you are not yet an IntelliJ IDEA user, you can download the newest version and it will already come bundled with the latest Kotlin plugin.

Enjoy quick code completion and highlighting

Sometimes writing code may not be as much fun as it could be, especially if you need to wait for the IDE to highlight your code and help you with completion. Our goal is to make code highlighting and completion seamless for you.

The new Kotlin plugin significantly improves performance for Kotlin code highlighting and completion.

Based on our tests, highlighting speed has improved by about 25% and code completion is now more than 50% faster, which brings it much closer to the performance level offered for Java.

Note that these numbers are just based on our tests. The improvements in your actual projects may not be as significant as our tests show, but you should notice much better performance.

Kotlin code highlighting in the new plugin

Here you can see a comparison of the speed of Kotlin code highlighting between the previous Kotlin plugin, version 2020.3, and the new one, version 2021.1. The results are based on our benchmark tests that check code highlighting in complex Kotlin files.

Faster Kotlin code highlighting

Kotlin code completion in the new plugin

And here is a comparison of the performance of Kotlin code completion between version 2020.3 and version 2021.1. The results are based on our benchmark tests that check code completion in complex Kotlin files.

Faster Kotlin code completion

Change signature with better IDE support

If you’ve used the Change Signature refactoring in previous versions of the Kotlin plugin, you may have encountered issues and limitations, as well as a lack of visibility regarding what went wrong in those cases.

Update to the new Kotlin plugin to reap the benefits of more than 40 bug fixes and improvements to the Change Signature refactoring.

Here are some of the most important improvements:

Evaluate custom getters right in the Variables view

Based on our research, the debugging experience for Kotlin requires significant improvements to deliver a better developer experience, and we already have a number of plans in the works to provide them.

This release provides a small but important improvement for evaluating properties in the Variables view.

Previously, during a debug session, you could only see the properties that didn’t have a custom getter and those with a backing field. Properties with a custom getter didn’t appear because they are represented as regular methods on the JVM. In version 2021.1 of the Kotlin plugin, you can see all such properties and evaluate them on demand by clicking on get() near the property name.

For example, when debugging the following code, you can execute the get() method to see the versionString value:

class LanguageVersion(val major: Int, val minor: Int) {
    val isStable: Boolean
        get() = major <= 1 && minor <= 4
    val isExperimental: Boolean
        get() = !isStable
    val versionString: String
        get() = "$major.$minor"
    override fun toString() = versionString
}
fun main() {
    val version = LanguageVersion(1, 4)
}

In the Debug window, you can see the values of the properties:

Debugging in Variables view

We would greatly appreciate it if you could try this feature out and provide your feedback in this ticket or as comments to this blog post.

Use code completion for type parameters

The new Kotlin plugin can now complete code for type parameters. Previously, you had to write this code manually without the benefit of the IDE’s assistance features.

Now code completion suggests functions and properties after generic functions and restores type arguments where needed. When you select such a function from the list, the IDE adds the correct type parameter to the preceding code.

In the following example, the IDE automatically adds the <String>() type:

Code completion for type parameters

After you apply the IDE’s suggestion, you’ll get the following code:

fun typeParametersAtCodeCompletion() {
    //  Function definition from stdlib:
    // public fun <T> emptyList(): List<T>
    val listA: List<String> = emptyList() // T is inferred from the context (explicit variable type)
    val listB: List<String> =
        emptyList<String>().reversed() // type argument for emptyList() is required to evaluate expression type
}

Review the structure of your Kotlin code with class diagrams

With the new release, you can review the structure of your Kotlin code via UML Class diagrams. To build a diagram, select Diagrams | Show Diagram… | Kotlin Classes in the Project View.

UML Class diagrams for Kotlin code

Currently, the diagrams only show inheritance and nesting relationships. Additional, more detailed association connections, like aggregation, construction, dependency, and others, will become available in future releases.

Benefit from other IDE improvements

Since the Kotlin plugin and the IntelliJ Platform have been moved to the same codebase and now ship simultaneously, you will also have the ability to do the following to benefit your Kotlin experience:

See also

Continue ReadingKotlin Plugin 2021.1 Released: Improved IDE Performance and Better Support for Refactorings

Kotlin Kernel for Jupyter Notebook, v0.9.0

This update of the Kotlin kernel for Jupyter Notebook primarily targets library authors and enables them to easily integrate Kotlin libraries with Jupyter notebooks. It also includes an upgrade of the Kotlin compiler to version 1.5.0, as well as bug fixes and performance improvements.

pip installConda install

The old way to add library integrations

As you may know, it was already possible to integrate a library by creating a JSON file, which we call a library descriptor. In the kernel repository, we have a number of predefined descriptors. You can find the full list of them here.

Creating library descriptors is rather easy. Just create a JSON file and provide a description section with a library description and a link section with a link to the library’s web page. Then add the repositories and dependencies sections, describing which repositories to use for dependency resolution and which artifacts the library includes. You can also add an imports section, where you list imports that will be automatically added to the notebook when the descriptor is loaded, such as init and initCell code snippets, renderers, and so on. When you are finished, save the created file and refer to it from the kernel in whatever way is most convenient for you. In this release, we’ve added some more ways to load descriptors. You can read more about how to create library descriptors here.

This method for integrating libraries is still supported and works particularly well when you are not the author of the library you want to integrate. But it does have some limitations:

  1. It requires additional version synchronization. The integration breaks if a new version of the library is released and a class that was used in the integration is renamed.
  2. It’s not that easy to write Kotlin code in JSON without any IDE support. So if your library provides renderers or initialization code, then you have to go through a potentially long process of trial and error.
  3. Transitive dependencies are not supported. If libraries A and B provide descriptors and library A depends on library B, then adding just the descriptor for library A is not enough, and you also need to run %use B.
  4. Advanced integration techniques are not allowed. See below for more info.

The new way to add library integrations

One of the best things about Kotlin notebooks (compared to Python notebooks) is that you do not have to think about dependencies. You just load the library you need with the @DependsOn annotation and use it. All transitive dependencies are loaded automatically, and you do not have to worry about environments or dependency version clashes. An added bonus is that it will work the same way on all computers. So far, however, there hasn’t been a way to define the descriptor mentioned above and to attach it to a library so you don’t have to create and load it separately.

Now there is such a way. You can now define the descriptor inside your library code and use a Gradle plugin to automatically find and load the ID. This means you do not have to write a separate JSON and %use directive.

If you are the maintainer of a library and can change its code, you may like the new method of integration. It currently utilizes Gradle as a build system, but if you use something else, feel free to open an issue and we will work on adding support for it.

Suppose you have the following Gradle build script written in the Kotlin DSL:

plugins {
    kotlin("jvm")
}

group = "org.example"
version = "1.0"

// ...

The published artifact of your library should then have these coordinates: org.example:library:1.0

You normally add your library to the notebook using the DependsOn file annotation:

@file:DependsOn("org.example:library:1.0")

Now suppose you need to add a default import and a renderer for this library in notebooks. First, you apply the Gradle plugin to your build:

plugins {
    kotlin("jvm")
    kotlin("jupyter.api") version "<jupyterApiVersion>"
}

Then, you write an integration class and mark it with the JupyterLibrary annotation:

package org.example

import org.jetbrains.kotlinx.jupyter.api.annotations.JupyterLibrary
import org.jetbrains.kotlinx.jupyter.api.*
import org.jetbrains.kotlinx.jupyter.api.libraries.*

@JupyterLibrary
internal class Integration : JupyterIntegration() {
    override fun Builder.onLoaded() {
        import("org.example.*")
        render<MyClass> { HTML(it.toHTML()) }
    }
}

It is supposed that MyClass is a class from your library and has the toHTML() method, which returns an HTML snippet represented as a string.

After re-publishing your library, restart the kernel and import the library via DependsOn again. Now you can use all the packages from org.example without specifying additional qualifiers, and you can see rendered HTML in cells that return MyClass instances!

Advanced integration features

Let’s take a look at some advanced techniques you can use to improve the integration. We’ll use the following set of classes for reference:

data class Person(
    val name: String,
    val lastName: String,
    val age: Int,
    val cars: MutableList<Car> = mutableListOf(),
)

data class Car(
    val model: String,
    val inceptionYear: Int,
    val owner: Person,
)

annotation class MarkerAnnotation

Subtype-aware renderers

In the descriptors using the old style, you can define renderers that transform cell results of a specific type. The main problem of this approach is that type matching is done by fully qualified type names. So if you define a renderer for a type A that has a subtype B, the renderer will not be triggered for instances of type B.

The new API offers you two solutions to this problem. First, you can implement the org.jetbrains.kotlinx.jupyter.api.Renderable interface:

import org.jetbrains.kotlinx.jupyter.api.*

class MyClass: Renderable {
    fun toHTML(): String {
        return "<p>Instance of MyClass</p>"
    }

    override fun render(notebook: Notebook) = HTML(toHTML())
}

It yields the following result:

Rendered MyClass

Another way to do the same thing has actually already been presented above:

render<MyClass> { HTML(it.toHTML()) }

This option is preferable if you want to keep integration logic away from the main code.

Variable converters

Variable converters allow you to add callbacks for variables of a specific type:

addTypeConverter(
    FieldHandlerByClass(Person::class) { host, person, kProperty ->
        person as Person
        if (person.name != kProperty.name) {
            host.execute("val <code>${person.name}</code> = ${kProperty.name}")
        }
    }
)

This converter creates a new variable with the name person.name for each Person variable defined in the cell. Here’s how it works:

Paul created

Annotations callbacks

You can also add callbacks for file annotations (such as the aforementioned DependsOn) and for classes marked with specific annotations.

onClassAnnotation<MarkerAnnotation> { classes ->
    classes.forEach {
        println("Class ${it.simpleName} was marked!")
    }
}

Here we are simply logging the definition of each class marked with MarkerAnnotation:

MarkerAnnotation

Cell callbacks

Descriptors allow you to add callbacks that are executed when the library loads (init) and before each cell is executed (initCell). The new integration method also allows you to add these callbacks with ease and provides support for callbacks triggered after cell execution. Let’s see how it works.

beforeCellExecution {
    println("Before cell callback")
}

afterCellExecution { _, result ->
    println("Cell [${notebook.currentCell?.id}] was evaluated, result is $result")
}

before-after-cell

Here you see a usage of the notebook variable, which provides some information about the current notebook.

Dependencies, renderers, and more

There are some other methods you can use to improve Jupyter integration, such as render, import, dependencies, repositories, and more. See the JupyterIntegration code for a full list.

Note that you can mark with @JupyterLibrary any class that implements LibraryDefinition or LibraryDefinitionProducer. There’s no need to extend JupyterIntegration.

All of the code from this section is provided here. You can also find a more complex example of integration in the Dataframe library.

Maven artifacts for your use case

We now publish a set of artifacts to Maven Central, and you are welcome to use them in your own libraries.

The kotlin-jupyter-api and kotlin-jupyter-api-annotations artifacts are used in the code-based integration scenario that was described above. You will not usually need to add them manually – the Gradle plugin does it for you. These artifacts may help in some situations, for example, if you don’t use Gradle or just want to use some classes from the API without integrating it.

If you just want to use the Kotlin REPL configuration and the compiling-related features that are used in the kernel, you may be interested in the kotlin-jupyter-shared-compiler artifact. This artifact was designed to be consistent with the IntelliJ Platform, so you can use it to make IntelliJ plugins.

kotlin-jupyter-lib-ext is a general-purpose library that includes functions for images and HTML rendering. You can load it from the notebook with %use lib-ext. It is not included in the kernel distribution because it may require additional dependencies in the future, and it is not a good idea to bundle them by default.

And finally, you can depend on the kotlin-jupyter-kernel artifact if you need the whole kernel bundled into your application. You can use the embedKernel method to start the kernel server.

Other artifacts have no clear use case and are just transitive dependencies of other ones.

If your use case is not covered, please open an issue or contact us in the #datascience channel of Kotlin Slack.

Kotlin 1.5.0 and bug fixes

The underlying Kotlin compiler version was updated to 1.5.0 pre-release. It doesn’t use the new JVM IR backend at the moment, but we’ll make that happen soon. The main thing is that we’ve fixed a bug in the REPL compiler that was affecting the updating of scripts’ implicit receivers, so performance should now be better for notebooks with a large number of executed cells.

A number of additional bugs have also been fixed, including these particularly weird ones:

  • Irrelevant error pop-ups in the Notebook client (#109)
  • Incorrect parsing of %use magic (#110)
  • Resolution of transitive dependencies with runtime scope didn’t work
  • Leaking of kernel stdlib into script classpath (#27)

Check out the release changelog for further details.

Let’s Kotlin!

Continue ReadingKotlin Kernel for Jupyter Notebook, v0.9.0

Kotlin 1.5.0-M2 Released – Ensure Smooth Migration to Kotlin 1.5.0

Kotlin 1.5.0-M2 is the last milestone release for Kotlin 1.5.0, which is coming this spring. So this is the last chance to make sure that your projects will successfully work with Kotlin 1.5.0.

Install 1.5.0-M2

If you migrate your projects now, you can save yourself time and energy in the future, when Kotlin 1.5.0 comes out, and you can help us provide urgent fixes before the release.

For example, if you try the new JVM IR backend, which is becoming the default in 1.5.0, and discover any issues now, we’ll try to deliver fixes before the release. You can report any issues you encounter to our issue tracker, YouTrack.

Note that Jetpack Compose only works with the new JVM IR backend. So if you’ve tried Jetpack Compose, you’ve already used the new backend.

Enjoy simplified configuration for preview releases

Previously, if you decided to use a preview release in your existing projects, you had to specify an additional Bintray repository in your Gradle files. Now all Kotlin preview artifacts are stored in Maven Central and there is no need to add the repository manually.

Save time! Install the M2 release, change the Kotlin version in your projects to 1.5.0-M2, and adjust any library dependencies if necessary.

Install 1.5.0-M2

Share your real-world cases with new language features

Have you had a chance to test out the experimental language features in Kotlin 1.4.30?

If you haven’t, give them a try now! And if you’ve already worked with them or have just been experimenting, you might have a good use case for us. 😉 Please don’t keep it in secret. Share it with us!

Our documentation team often gets feedback like this 🗣:

“Please add more samples to documentation”.

“It’s not clear without real-world examples”.

“Could you provide samples with detailed explanations?”

Please help us provide more real-world examples in our language docs and make it more helpful for developers like you.

Share a language feature sample

Don’t miss the Kotlin 1.5.0 videos

The Kotlin YouTube channel is available for those of you who like watching videos. We are continually updating the channel with new videos, and we plan to publish a video series dedicated to Kotlin 1.5.0. Be the first to watch 🎥!

Subscribe to Kotlin YouTube


Haven’t validated your projects with Kotlin 1.5.0 yet? Install 1.5.0-M2 now to avoid issues in the future.

Continue ReadingKotlin 1.5.0-M2 Released – Ensure Smooth Migration to Kotlin 1.5.0

kotlinx.serialization 1.0 released

We are happy to share with you the release of version 1.0 of our multiplatform serialization library, kotlinx.serialization. As the first stable version of the library, we can finally consider it production-ready!

Whether you are writing Android apps, using Kotlin Multiplatform Mobile, creating server-side services, or building web frontends with Kotlin/JS – kotlinx.serialization comes with a simple but powerful pure-Kotlin API, which makes it effortless to parse JSON into type-safe Kotlin objects, and vice versa. To celebrate this release, we want to provide a brief overview of some of the production-ready features which are provided with kotlinx.serialization 1.0, and see what sets our library apart from other solutions.

But before we dive in, we would like to invite you to our Kotlin 1.4 Online Event, where Leonid Startsev will talk in more detail about the past, current, and future of kotlinx.serialization. Don’t miss it!

Register for the Kotlin 1.4 Online Event

Serializing & deserializing your first Kotlin object with kotlinx.serialization

Generally, serialization is a task that comes up quite frequently in software projects. Mobile apps or web frontends are likely to consume APIs which return JSON as a plain-text format for objects. Server-side applications and backend services often need to accept and respond to requests which are formatted using JSON. And even if you are looking to persist information on disk, using JSON as a human-readable format is a popular choice.

As you can see, the process of (de)serializing Kotlin objects is one that you might encounter sooner or later in your project as well. Choosing kotlinx.serialization makes this whole process very straightforward: After adding the library to your project, turning a basic Kotlin object into its JSON representation and back is as simple as marking its class with the @Serializable annotation, and using the provided encodeToString and decodeFromString<T> extension functions on the Json object:

import kotlinx.serialization.*
import kotlinx.serialization.json.*

@Serializable
data class User(val name: String, val yearOfBirth: Int)

fun main() {
   // Serialization (Kotlin object to JSON string)

   val data = User("Louis", 1901)
   val string = Json.encodeToString(data)
   println(string) // {"name":"Louis","yearOfBirth":1901}

   // Deserialization (JSON string to Kotlin object)

   val obj = Json.decodeFromString<Account>(string)
   println(obj) // Account(name=Louis, yearOfBirth=1901)
}

Of course, kotlinx.serialization isn’t the only library you can use to perform such serialization-related tasks. In the JVM ecosystem, there are a number of other libraries to work with JSON. However, the most popular choices available are not necessarily Kotlin-first, and might not be available for Kotlin Multiplatform projects at all. Even beyond this, there are excellent reasons to choose kotlinx.serialization for your project.

Why choose kotlinx.serialization?

Several features and design choices included in kotlinx.serialization set it apart from other libraries, and generally help make it more enjoyable to use its functionality. Let’s take a closer look at a selection of them.

Kotlin through and through

Not only is kotlinx.serialization written in pure Kotlin, and available on all Kotlin Multiplatform targets, including Kotlin/Native and Kotlin/JS. Its serialization functionality is also built with the Kotlin type-system in mind. Whether you’re trying to serialize a data class with default initializers for its properties, a singleton object, or trying to deserialize a generic List<T>: kotlinx.serialization always behaves as you would expect. This is best seen when looking at a concrete example, which turns a list of complex project objects (described by a data class) into its JSON representation, and back:

@Serializable
data class Project(
   val name: String,
   val owner: Account,
   val group: String = "R&D"
)

@Serializable
data class Account(val userName: String)

val moonshot = Project("Moonshot", Account("Jane"))
val cleanup = Project("Cleanup", Account("Mike"), "Maintenance")

fun main() {
   val string = Json.encodeToString(listOf(moonshot, cleanup))
   println(string)
   // [{"name":"Moonshot","owner":{"userName":"Jane"}},{"name":"Cleanup","owner":{"userName":"Mike"},"group":"Maintenance"}]

   val projectCollection = Json.decodeFromString<List<Project>>(string)
   println(projectCollection)
   // [Project(name=Moonshot, owner=Account(userName=Jane), group=R&D), Project(name=Cleanup, owner=Account(userName=Mike), group=Maintenance)]
}

As you can see, even the type-safe deserialization of collections with generics is handled by kotlinx.serialization just as expected. This certainly isn’t the norm, because collections on the JVM are normally affected by type erasure. As such, other libraries would require you to use workarounds like using explicit type-tokens in this situation. Because kotlinx.serialization also integrates using a compiler plugin, its out-of-the-box behavior (which you can see with the projectCollection example) is already what you would expect – no workarounds required!

Because we want to make sure that you can catch as many possible issues before even starting your application for the first time, kotlinx.serialization also strives for compile-time safety. For example, not explicitly marking the Account class to be @Serializable in the example above would result in the compile-time error Serializer has not been found for type 'Account', making it easy to pinpoint and fix the issue ahead of time instead of experiencing a crash.

Polymorphic serialization

kotlinx.serialization makes it possible to comfortably and securely deal with inheritance hierarchies of objects to serialize – a traditionally sensitive, but much-desired feature. Because the library is aware of Kotlin-specific type system concepts, the most straightforward way to use polymorphic serialization is to build a sealed class hierarchy, where all subclasses are explicitly marked as @Serializable. Because sealed class hierarchies are known at compile time, the kotlinx.serialization plugin can use this information, and the code required to serialize sub- and superclasses stays concise:

@Serializable
sealed class Message {
   abstract val content: String
}

@Serializable
data class BroadcastMessage(override val content: String) : Message()

@Serializable
data class DirectMessage(override val content: String, val recipient: String) : Message()

fun main() {
   val data: List<Message> = listOf(
       DirectMessage("Hey, Joe!", "Joe"),
       BroadcastMessage("Hey, all!")
   )
   val string = Json.encodeToString(data)
   println(string)
   // [{"type":"DirectMessage","content":"Hey, Joe!","recipient":"Joe"},{"type":"BroadcastMessage","content":"Hey, all!"}]

   val obj = Json.decodeFromString<List<Message>>(string)
   println(obj)
   // [DirectMessage(content=Hey, Joe!, recipient=Joe), BroadcastMessage(content=Hey, all!)]
}

As you can see with the string variable, kotlinx.serialization intelligently adds a type key to your JSON object containing information about the specific subtype – without you having to specify this behavior manually. When you’re in control of both client and server, this makes it possible for you to easily structure messages using inheritance relationships, without having to manually try and deduce subtypes on the other end.

While sealed classes are the most convenient way to use polymorphic serialization with kotlinx.serialization, and can already cover a large number of use cases, the library actually also offers functionality that goes beyond these closed hierarchies. To learn more about this functionality, check out the section on polymorphism in the guide.

Strong customizability

Especially when communicating with external systems and APIs, you might not be in full control over the exact shape in which you receive JSON-formatted messages. On the other hand, you might feel the need to adjust the output that kotlinx.serialization generates to make sure it is accepted by the remote you are communicating with.

Kotlinx.serialization comes with a rich configuration DSL which you can use to adjust the way it generally treats input and generates output, modifying general settings like enabling pretty-printing, lenient parsing, or ignoring unknown keys. For class- or object-specific settings, you can use annotations to customize their behavior, for example, to rename fields (@SerialName) or exclude them from the serialization process (@Transient). These annotations, among a number of others, are also covered in the guide. If your use case requires it, you can even provide completely custom serializers for specific types of objects.

Combining these features allows you to shape the behavior of the library to exactly match the requirements and specifications you have for your serialized format.

Framework integrations

While kotlinx.serialization with its concise interfaces can be used regardless of other libraries included in a project, a number of frameworks also provide direct integrations to use kotlinx.serialization. Here are some examples we want to highlight:

  • If you are using Ktor as a server-side framework, you can use the provided official integration with kotlinx.serialization together with content negotiation, making it possible to receive and respond with Kotlin objects directly for incoming and outgoing requests. The Ktor-Clients counterpart, which is available in Kotlin Multiplatform projects, also provides JSON payload processing via kotlinx.serialization.
  • Spring MVC has recently added support for kotlinx.serialization, and a similar integration has been proposed for Spring WebFlux, thanks to Sébastien Deleuze.
  • Http4k provides first class support for marshalling to and from HTTP messages using kotlinx.serialization.
  • Fuel provides an extension package to use kotlinx.serialization in your Android HTTP client.
  • If you are working with MongoDB, the KMongo library provides object mapping through kotlinx.serialization.
  • If you are using Retrofit 2 to turn your HTTP APIs into Kotlin interfaces, you can use the serialization converter by Jake Wharton to integrate with kotlinx.serialization.

We are very excited about the growing number of third-party projects which integrate directly with kotlinx.serialization – and now that our library has reached a production-ready state, we hope to see many more such integrations soon!

Multi-format future

With version 1.0, all functionality related to working with JSON is stable and production-ready – but kotlinx.serialization is not stopping there! Besides JSON, the team is working on additional support for the HOCON, ProtoBuf, CBOR, and Properties serialization formats. While these formats are still being designed and developed, and as such have varying degrees of stability and platform compatibility, you can already try them out. They are available as separate artifacts, which you can find in the guide together with a short description of the format’s state.

A number of community-maintained formats like BSON, XML, and YAML also exist alongside the formats the team is working on officially – but please note that these are created and maintained by members of the community, and as such may receive delayed updates by their maintainers.

Now that we have highlighted a number of features that make kotlinx.serialization comfortable to use, we hope you have a good idea why you might want to choose the library for your current (or next) project – which is a quick process!

Adding kotlinx.serialization to your project

To start using kotlinx.serialization in your project, simply add the compiler plugin and runtime library to your project. In your build.gradle(.kts), add the following entry to the plugin block:

plugins {
   kotlin("plugin.serialization") version "1.4.0"
}

Next, add the runtime library dependency to your dependencies block in your build.gradle(.kts) file. If you are working in a Kotlin Multiplatform project, it’s enough to add the dependency to your common target dependencies block – all platform-specific dependencies will automatically be added for you:

dependencies {
   implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0")
}

At this point, you’re ready to start using kotlinx.serialization! Feel free to experiment with the samples included in this blog post, try one of your own use cases, or play around with the examples which accompany the guide.

Learning more & giving feedback

We hope you enjoyed this brief overview of kotlinx.serialization! To find out more information, including always up-to-date installation instructions, visit its home on GitHub. Be sure to check out the kotlinx.serialization guide, which contains detailed information about basic and advanced features of the library, and covers many of the topics mentioned in this blog post in more detail. If you run into any trouble using the library, you can seek help in the project’s issue tracker, or in the #serialization channel on the Kotlin Slack.

For an exclusive look behind the scenes and a more in-depth explanation of our serialization library, this is also a good time to invite you once more to the kotlinx.serialization talk by Leonid Startsev during the Kotlin 1.4 Online Event – we look forward to seeing you there!

Register for the Kotlin 1.4 Online Event

If you have previously used kotlinx.serialization, use the changelog and migration guide to find out what has changed and how to upgrade your projects to the stable release.

A thank you from the team

We want to say “thank you” to everyone who gave us feedback, submitted pull requests, used kotlinx.serialization pre-1.0, or contributed in any other way to the library. Your input was extremely valuable in helping the team deliver a robust, easy-to-use, Kotlin-first, multiplatform serialization library. The over 700 issues you reported before our first stable release helped squash bugs and iron out any wrinkles in the design before this first stable release. As we continue to evolve the project, we hope that we can count on your continued support and feedback to help us keep improving and innovating. So: Thank you, everyone – and have a nice Kotlin!

Continue Readingkotlinx.serialization 1.0 released

Dark Theme Is Now Available in Toolbox App 1.18.

It’s been a while since you made this wish, and now we’ve finally made it come true! We are happy to introduce the frequently requested feature – the Dark Theme. :tada:

Don’t have the Toolbox App yet? Click the link below to download the free Toolbox App and start working with the theme you like the most.

Download now

You shouldn’t wait any longer to see it in action. Just update your Toolbox App to version 1.18, if you haven’t set the Toolbox App to update automatically and select the Dark Theme in the “Appearance & Behavior” section of the Toolbox App Settings.

Dark Theme

Currently, the app offers two options – Light or Dark Theme – which you can change manually. Go to the Toolbox App Settings and choose the theme you like under the “Appearance & Behavior”.
Theme Settings

Bug Fixes 🛠

In the same release, we’ve fixed the following issues:

TBX-4898 – Generation of shell scripts on macOS for Android Studio 4.0 and 4.1 now works correctly.
TBX-4985 – Toolbox now correctly updates taskbar shortcuts on Windows.
TBX-5031, TBX-5066 – The uninstall process on Windows now works correctly.
TBX-5199 – Toolbox now updates Linux .desktop files if there is a broken symlink.
TBX-5233 – We’ve fixed a bug that caused Android Studio 4.1 not to start from the Toolbox App on macOS.

See the full list of fixed issues here.

As always, the Toolbox App team is happy to get your feedback! Leave us a message in our issue tracker or on Twitter by mentioning @JBToolbox.

Stay safe, and stay productive!
The Toolbox App team

Continue ReadingDark Theme Is Now Available in Toolbox App 1.18.

Kotlin Multiplatform Mobile goes Alpha

Kotlin Multiplatform Mobile (KMM) is an SDK that allows you to use the same business logic code in both iOS and Android applications. Today KMM goes Alpha, and you can start sharing business logic in your mobile apps with it right away. It includes the new KMM Plugin for Android Studio, which allows you to write, run, test, and debug shared code in the same IDE. Join such great teams as VMWare, Autodesk and Yandex who are sharing code in their mobile apps using Kotlin. It has never been so easy!

file

What is Kotlin Multiplatform Mobile?

Kotlin Multiplatform Mobile (KMM) is an SDK for cross-platform mobile development provided by JetBrains. It uses the multiplatform capabilities of Kotlin and includes various tools and features designed to make the end-to-end experience of building mobile cross-platform applications as enjoyable and efficient as possible.

The Android and iOS versions of an application often have a lot in common, but they can also differ significantly – especially in terms of their UI – from subtle variations in scrolling behavior to completely divergent navigation logic. At the same time, the application’s business logic, including such features as data management, analytics, and authentication, is often identical. That’s why it’s natural to share some parts of an application across platforms while keeping other parts completely separate.

With KMM, you can get this flexibility and retain the benefits of native programming. Use a single codebase for the business logic of iOS and Android apps and write platform-specific code only where it’s necessary, to implement a native UI or when working with platform-specific APIs.

file

KMM is seamlessly integrated with your mobile project. Shared code, written in Kotlin, is compiled to JVM bytecode with Kotlin/JVM and to native binaries with Kotlin/Native, so you can use your KMM business-logic modules just like any other regular mobile library.

Sharing Kotlin code between mobile platforms has already saved a lot of time and effort for many companies. Here are some inspiring stories:

  • Quizlet migrated their business logic from a shared JavaScript approach to KMM and drastically improved the performance of both their Android and iOS applications.
  • Fastwork introduced KMM for the domain and data layers of their application to share business logic and API service between mobile platforms, significantly boosting their team’s productivity.
  • Yandex.Disk started out by experimenting with the integration of a small feature, and when the experiment proved successful, they implemented their whole data synchronization logic in KMM.

The remarkable results achieved by these and many over teams have been a big part of our inspiration, and we hope that their stories will encourage you to start sharing code between mobile platforms with KMM.

Enjoy creating mobile apps with KMM

KMM is still quite new to the mobile development world, but we believe that it is a true game-changer. That’s why we allocated a separate team inside Kotlin to push KMM forward and provide the best developer experience for the creation of cross-platform mobile applications with Kotlin.

As a first step toward this, today we are happy to present to you the first preview of the KMM plugin for Android Studio along with the new KMM developer portal.

Let’s start our KMM Journey!

Work in a familiar environment

With the new KMM plugin, you can write, run, test, and debug shared code in Android Studio, without switching to other IDEs. To install it, select Preferences | Plugins, search for the Kotlin Multiplatform Mobile plugin in Marketplace, and press the Install button.

Configure a new application in a few clicks

With the New Kotlin Multiplatform Mobile Project wizard, you can create a ready-to-run mobile application project with a shared codebase in just a few clicks. To see how it works on both platforms, just select the run configuration you need and click the Run button.

file

The generated project will contain examples of how to connect to platform-specific API and basic test coverage. You can use this wizard to explore the basic features of KMM or as a scaffolding tool for your new KMM production application.

Follow this tutorial to install the plugin and create your first multiplatform application with the wizard.

Introduce KMM to your existing project in one step

You also can start your KMM journey right in your current project: the shared Kotlin code can be easily integrated into your existing code just like any other regular dependency. The New Kotlin Multiplatform Mobile Module wizard will help you add a new KMM module to your project, so you can use the code you’ve already written in Kotlin and refactor it to make it compatible with iOS.

Check out this guide to integrating KMM into existing projects to learn how to design the architecture of multiplatform projects and organize the migration to it.

Work with both platforms within one IDE

You no longer need to switch IDEs and have Xcode running to check that your code works correctly on both mobile platforms. With the new plugin, you get integration with your iOS device and simulator directly in Android Studio. This gives you the following capabilities:

  • Run and debug the iOS application on the simulator or a device with the predefined run configuration.
  • Run and debug common and iOS specific tests on the iOS simulator by simply clicking the gutter icon on a test class or method.

For both the application and tests you can set breakpoints and debug your code on iOS.

Integrate with the iOS ecosystem without any overhead

As mentioned above, KMM is seamlessly integrated with your mobile project. For Android, you can use Kotlin for every part of your project. At the same time, KMM provides tight integration with the iOS development process, because of Kotlin/Native’s interoperability with Objective-C/Swift, the integration with the CocoaPods dependency manager, and the ability to use platform-specific APIs with the expect/actual pattern.

Enjoy working with Kotlin from Swift code with Kotlin/Native

Kotlin/Native provides bidirectional interoperability with Objective-C/Swift. Kotlin modules can be fully used in Swift/Objective-C. You can use Objective-C frameworks and libraries in Kotlin code, as well as Swift libraries if their API is exported to Objective-C with @objc.

Learn more about Kotlin/Native’s interoperability with Swift/Objective-C.

Easily manage iOS dependencies

Kotlin/Native provides integration with the CocoaPods dependency manager. You can add dependencies on Pod libraries stored in the CocoaPods repository or locally, and you can also use multiplatform projects with native targets as a CocoaPods dependency (Kotlin Pod). Manage Pod dependencies directly in Android Studio and enjoy full coding support, including highlighting and completion.

This is how the typical KMM library configuration looks:

kotlin {
	android()
     ios()
    
     cocoapods {
         summary = "CocoaPods test library"
         homepage = "https://github.com/JetBrains/kotlin"
         pod("AFNetworking", "~> 4.0.0")
         podfile = project.file("../ios-app/Podfile")
     }
 }

Connect the library to your iOS project as a Kotlin Pod by adding its name and path to the Podfile:

 use_frameworks!

 target 'ios-app' do
         pod 'kotlin_library', :path => '../kotlin-library'
 end

Learn more about CocoaPods integration.

Learn how to create better multiplatform mobile apps on the new Developer Portal

The new KMM Developer Portal is designed to make your journey more comfortable and productive, from your very first experience with KMM all the way through to using it in production.

The documentation section is your trusted resource when you are working with KMM. You will find content for all levels of expertise, from tutorials to get you started to more advanced development topics. It contains useful information about common tasks, like organizing networking and data storage layers and even organizing the development process around KMM.

Pick up new ideas about the benefits of using KMM in your application by learning from the first-hand experience of a variety of teams who are already using KMM in their products in the case studies section.

The power of the community

We are indebted to the following companies and independent developers whose investment of time, knowledge, and expertise were crucial for this release: Kevin Galligan, Alec Strong, Arkadii Ivanov, Ben Asher, John O’Reilly, Louis CAD, Kris Wong, Aleksey Mikhailov and and many other incredible engineers. Thank you for reporting issues on YouTrack, participating in product research and interviews, sharing stories about your experience using KMM, and creating incredible multiplatform libraries!

We also want to thank the teams who helped us create content for the new Developer Portal: Touchlab, IceRock, and Kodein Koders. Your work will help thousands of developers delve deeper into Kotlin Multiplatform Mobile and harness its full power.

You rock, folks!

Try it now

With all these cool features, we are happy to announce that KMM is now in Alpha. This means that the Kotlin team is fully committed to improving this technology and helping it evolve. It is also a signal that the product will develop quickly. We’ll listen to your feedback and provide fixes and improvements as soon as possible. Please help us increase the stability of KMM by reporting any issues you find via our tracker.

Going Alpha means that everything is ready for you to start using KMM to share business logic code between mobile platforms. You can create a new project or easily integrate a KMM module into existing ones. In both scenarios, the work can be done with minimal cost and you can always go back to fully native development. The community is growing fast, and you can influence the development of the whole ecosystem by participating in it.

So now is a great time to start using KMM!

To get the best experience of taking a deep dive into KMM and to discuss all the features you plan to explore, join the community of multiplatform enthusiasts in Slack (get invite here) and subscribe to the “kotlin-multiplatform” tag on Stack Overflow.

Though we try our best, we can’t guarantee a smooth migration just yet. However, we’ll try to avoid compatibility issues as much as possible by using feature flags and providing migration guides for new versions.

Share your feedback

This release is just the beginning of the journey, but we need your help along the way. We look forward to all your feedback, both bad and good. Become an inspiration for others by sharing your stories of using Kotlin Multiplatform Mobile, and please share any ideas you have about how we can improve KMM.

Let’s Kotlin!

Continue ReadingKotlin Multiplatform Mobile goes Alpha

JetBrains Toolbox 2020.2. Summary

All tools in the JetBrains Toolbox and included in the All Products Pack subscription have been updated to their new 2020.2 versions. Below you can read about what the updates bring to particular tools you use from the toolset, and you can update to the newest version via the Toolbox App or from the tool itself.

IntelliJ IDEA

IntelliJ IDEA 2020.2 lets you review and merge GitHub pull requests right from inside the IDE, quickly navigate between warnings and errors in a file through the new Inspections Widget, view the full list of issues in a current file with the Problems tool window, and get notified if your changes break other files. You can use Jakarta EE, and get better support for Quarkus, Micronaut, and OpenAPI.
WebStorm

WebStorm 2020.2 comes with a long-awaited option for using Prettier as the default formatter, best-in-class (now we can finally say so!) support for Vue, new intentions for JavaScript, full support for GitHub pull requests, and much more!
PyCharm

PyCharm 2020.2 comes out with a lot of improvements to increase your productivity and code quality. Now you can perform the full Pull Request workflow without leaving your IDE, using PyCharm’s newly designed UI. You can also easily catch exceptions in your code with the new preview window that will stop the code execution and point out the line of code that is generating the problem. Finally, changing method signatures and renaming classes have been made easier with the new in-place refactoring feature. Just type your changes in the editor, review it, and apply it to all its usages.
RubyMine

RubyMine 2020.2 introduces a new way to review problems in code, a whole host of new intention actions, support for the Liquid template language, full support for GitHub pull requests, and many more new features for Ruby, Rails, JS, and database tools.
ReSharper

ReSharper 2020.2 brings new inspections and quick-fixes for C#8 and nullable reference types, the much-awaited Code Cleanup on Save, and a revamped Unit Test Runner. Also, ReSharper C++ brings you to the next level of Unreal Engine development and comes with a lot of improvements for C++/CLI support, navigation, and code analysis.
Please note the new licensing for ReSharper covered in this blog post.
icon_AppCode

AppCode 2020.2 is here with initial Swift Package Manager support, speed improvements for code completion, navigation, and highlighting, the Change Signature refactoring for Swift, a brand new Problems view and inspection widget, full support for GitHub pull requests, and more!
PhpStorm

PhpStorm 2020.2 is a major update for the IDE. It brings support for PHP 8 Union Types, a new control flow engine for PHP, full GitHub pull requests workflow support inside the IDE, a brand-new Inspection Widget, OpenAPI support via a plugin, and more.
GoLand

GoLand 2020.2 includes new features for Go Modules, better presentation of possible problems and weak places in your code, new code inspections, new code editing features, such as the long-awaited Add Caret Per Selected Line, updates for version control including WSL2 support for Git on Windows, and more!
Rider

Rider 2020.2 delivers several highly requested features such as the Localization Manager to help you work with resources in your app or website, and Shader support in our Unity integration. We’ve completely reworked the Unit Test Runner and the debugger API to make them faster, more powerful, and more stable.
CLion

CLion 2020.2 covers a wider variety of C++ projects by adding Makefile projects and polishing CMake support. Thanks to better compliance with the C++20 standard, many reworked code analysis checks, and new unit testing abilities, writing high-quality modern C++ code has never been easier.
DataGrip

DataGrip 2020.2 brings a separate editor for cell values, DML preview in the data editor, Google BigQuery dialect, and more!

With these releases out, we’ve already started working on further improvements. This means that early access programs for 2020.3 should open very soon. Stay tuned!

Your JetBrains team

Continue ReadingJetBrains Toolbox 2020.2. Summary

Kotlin 1.4 Released with a Focus on Quality and Performance

You can read this blog post in other languages:
日本語, Français, 한국어, Español, Português, Русский, 简体中文

Today we’re releasing Kotlin 1.4.0! Over the past years, we’ve been working hard on making Kotlin a programming language that is fun, enjoyable, and productive to work with. To continue our pursuit of this goal with this version of Kotlin, we put a lot of energy and effort into improving the performance and quality of Kotlin and its tooling. We are also excited to announce support for several new language features, including the long-awaited SAM conversions for Kotlin interfaces.

file

To help you get the most out of the changes and improvements introduced in Kotlin 1.4, we’re inviting all of you to the Kotlin 1.4 Online Event, where you will be able to enjoy four days of Kotlin talks, Q&As with the Kotlin team, and more – completely free.

Community and ecosystem

More than 5.8 million people have edited Kotlin code in the last 12 months, and the numbers are constantly growing:

file

We’re delighted to see how popular Kotlin is becoming! The numbers of active users – we’ll explain this metric in more detail in a future blog post – have been especially encouraging. Here, we are seeing a 1.5-fold increase over the previous year’s figures.

According to the StackOverflow Developer Survey 2020, Kotlin has climbed to 13th place among the most popular programming languages for professional developers, and we’re happy to see that Kotlin is one of the top 5 most loved languages.

Many companies have picked Kotlin as their language of choice, and are successfully using it on all platforms. We’re happy to see this tendency, and we’re tremendously grateful that so many of these companies have made case studies available for the community to read and learn from. Here are just a few amazing examples of software recently developed in Kotlin:

Our Kotlin communities are also growing rapidly. Over 30,000 Kotlin developers are now exchanging knowledge and supporting each other on Slack and Reddit, and more than 90,000 people follow our official Twitter account for tips, tricks, and announcements. With over 200 user groups worldwide, the Kotlin community is thriving and growing. We’re thankful to all of you for helping spread the word, sharing your knowledge, and supporting your fellow Kotlin developers. The warm, welcoming atmosphere you create is what makes exploring Kotlin together such a delightful experience. It wouldn’t be the same without you.

Kotlin 1.4 Online Event

We want to make sure that you have a great experience using Kotlin 1.4, and we want you to have a good idea of where we are taking the language next. This is why we are happy to invite all of you to our Kotlin 1.4 Online Event!

It consists of four days packed with knowledge about Kotlin and the future of the language and its ecosystem: We’ll discuss the new changes and improvements we made with Kotlin 1.4, and we’ll share our future plans for the language. Our Kotlin team members will answer your questions in daily Q&A sessions. Submit your questions in advance by tweeting them with the #kotlin14ask hashtag, or using this form.

The Kotlin 1.4 Online Event will be streamed on October 12–15, and you can register for free here:

Register for Kotlin 1.4 Online Event

We look forward to seeing all of you there!

Focusing on quality

Our main focus for this release was improving the overall development experience with Kotlin, including improved IDE performance and stability. Our goal is to make Kotlin users as productive as possible, and we focused on improving the things that are most important to users, so they feel even happier when using it!

We’ve reviewed and fixed more than 60 performance issues, including many that were causing IDE freezes or memory leaks. During the EAP phase for Kotlin 1.4.0, we gathered a lot of positive feedback indicating that the overall experience is now much more enjoyable!

When you are working with a project and open a large Kotlin file for the first time, you now see its content with highlighting much sooner. In most cases, highlighting is now 1.5-4 times faster:

We have also significantly improved the time it takes for autocomplete suggestions to appear. The following graph shows an overview of the average autocomplete response times that Kotlin users experience. The number of cases in which completion takes more than 500 ms has been cut nearly in half:

file

Note that these latest changes, including the code highlighting speed-up, require IntelliJ IDEA 2020.1+ and Android Studio 4.1+.

Performance improvements are an ongoing process, and we have many more enhancements planned, like continuing to work on eliminating freezing and making typing smoother. We’ve already started integration with the new experimental Kotlin compiler frontend that will make the IDE a lot faster. This is a huge task that requires many parts of the plugin to be rewritten, but it will boost performance in many areas of the IDE, including code completion, syntax highlighting, and compiler error reporting.

New IDE functionality

Our mission at JetBrains is to make software development a more productive and enjoyable experience, so we naturally want to make sure that the tooling surrounding Kotlin is excellent and makes coding Kotlin as easy as possible.

To make it easier for you to work with coroutines, and especially to pinpoint bugs in your concurrent applications, we’ve introduced the Coroutine Debugger. We’re going to expand on its initial feature set to provide the functionality most needed by the community, so please share your feedback with us using one of our channels or in the comments section below.

We are also introducing a new flexible Kotlin Project Wizard. This new wizard provides a single place for you to create and configure Kotlin projects of different types, making it easy to get started even with more complex structures such as multiplatform projects.

More than 40 new quick-fixes, intentions, and inspections have been added with Kotlin 1.4.0, and will be available exactly when you need them – when you modify your code, and press Alt+Enter to see what’s available in your specific context.

New compiler

For quite some time now, we’ve been working on a new Kotlin compiler that will advance the evolution of Kotlin in terms of performance and extensibility. The main goals for the new compiler are that it should be really fast, unify all the platforms that Kotlin supports, and provide an API for compiler extensions. We’re introducing new parts step by step, so that they reach the user as soon as possible. With Kotlin 1.4.0, we’re releasing several parts from this ongoing effort:

We’re actively working on a new frontend implementation, which will provide the biggest performance increase in the compiler pipeline. The frontend is the part of the compiler that parses the code, resolves names, performs type checking, and more, so it affects the IDE performance as well. A preview of it will be available in future releases, stay tuned!

Language features

Kotlin 1.4 comes with many new features:

Library improvements

Our general priority for the standard library is to improve consistency, both across different platforms and among the operations themselves. In this release, the Kotlin standard library gets new collection operators, delegated properties improvements, the double-ended queue implementation ArrayDeque, and much more.

You can use the standard library in “common” code – the code shared between different platforms, be they Android & iOS or JVM & JS. We’re gradually extending the common library and adding or moving missing functionality to it.

It is also no longer necessary to declare a dependency on the stdlib in any Gradle Kotlin project, whether you are targeting a single platform or working in a multiplatform project. Starting with Kotlin 1.4.0, this dependency is added by default.

We’re working on other parts of the Kotlin ecosystem:

Kotlin/JVM

We encourage you to try out the new Alpha Kotlin/JVM backend for your regular projects and share your feedback! Along with unifying the compiler pipelines, this effort will help us bring compiler extensions like Jetpack Compose to the Kotlin community more quickly.

Language features specific to Kotlin/JVM:

Kotlin/JS

Kotlin 1.4.0 comes with a new Gradle DSL and an Alpha version of the new Kotlin/JS compiler backend, among other features.

  • The new Gradle DSL adds support for configuring CSS and style loaders from the DSL, it includes various improvements related to npm dependency management and improves control over the Dukat integration.
  • The new Kotlin/JS compiler backend gives a taste of the future for Kotlin/JS. It includes optimizations and features such as the automatic generation of TypeScript definitions from Kotlin code, smaller binaries and bundles, a modernized way to expose Kotlin functionality to JavaScript, and more.

Kotlin/Native

Kotlin/Native got a significant number of new features and improvements, including:

The current automatic memory management implementation in Kotlin/Native has limitations when it comes to concurrency and we are working on a replacement for it.

An important focus for Kotlin/Native is making it seamless for Kotlin Multiplatform Mobile, but it’s not limited to this.

Kotlin Multiplatform

Making Kotlin a great multiplatform solution is one of our top priorities. We promised some important improvements at KotlinConf, and we’re happy to report on what we’ve delivered:

We’re working on an Android Studio plugin for running, testing, and debugging Kotlin code on iOS devices and simulators. The first public preview is going to be released very soon, so please stay tuned.

We’re soon going to release a bunch of materials created with the help of Kotlin community members explaining how you can use Kotlin Multiplatform Mobile (KMM) technology to target specifically mobile use-cases in which code is shared between Android and iOS.

Despite the major focus now being on mobile targets, the Web target for Kotlin Multiplatform is already actively used by JetBrains to build and ship JetBrains Space. Web target continues to be an important strategic investment for Kotlin.

More details

You can find detailed descriptions of new features on the Kotlin 1.4 What’s New page and documentation, and read more about migrating to Kotlin 1.4.

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.

How to help us improve Kotlin

The Kotlin plugin in IntelliJ IDEA and Android Studio can collect anonymized statistics about how you use its functionality. We kindly ask you to opt in to these statistics!

This anonymous data greatly helps us understand our users better, see what works, what is causing difficulties, and where we should direct our focus. To enable statistics, go to Preferences, open Appearance & Behaviour | System Settings | Data Sharing and activate the Send usage statistics checkbox.

Top issue reporters since Kotlin 1.3

We’d like to thank all the members of the community who helped us make this release better by reporting issues to YouTrack! We’ve made a list of the top 20 reporters and would like to thank them specifically:

Igor Wojda (145 issues); Louis CAD (87 issues); Marc Knaup (86 issues); AndroidDeveloperLB (83 issues); Robert Stoll (68 issues); Morgan Bartholomew (62 issues); Victor Turansky (54 issues); Guan Tianyi (51 issues); Scott Pierce (38 issues); Andreas Malik (37 issues); Steven Schäfer (37 issues); Björn Kautler (36 issues); Róbert Papp (34 issues); Toshiaki Kameyama (30 issues); Nicholas Bilyk (29 issues); Michael Bailey (26 issues); Jake Wharton (25 issues); Lamberto Basti (24 issues); Serge Pro (23 issues); Egor Andreevici (21 issues).

Start using Kotlin 1.4 right now

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

In Gradle and Maven, use 1.4.0 as the compiler version. See the docs for Gradle and for Maven.

IntelliJ IDEA and Android Studio automatically prompt you to update the Kotlin plugin to version 1.4.0. You can also open Preferences | Plugins and update the Kotlin plugin manually.

The command-line compiler can be downloaded from the GitHub release page.

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

The versions of libraries from kotlin-wrappers (kotlin-react etc.) can be found in the corresponding repository.

The latest IDE performance improvements, including the code highlighting speed-up, require IntelliJ IDEA 2020.1+ and Android Studio 4.1+.

If you run into any problems with the new release, you can find help on Slack (get an invite here) and report issues in our YouTrack.

Thank you!

We’re really grateful to everyone who has tried out and given us feedback on the Kotlin EAPs and experimental features. We are developing the Kotlin language together with you, and making many design decisions based on your invaluable input. Keeping this fast and effective feedback loop going with the community is really important to help Kotlin become the best it can be!

We want to say a big thank you to all our external contributors whose pull requests were included in this release. You helped us make this release happen!

We’re grateful to all members of our community who are creating so many amazing things with Kotlin. Kotlin 1.4: One for all!

Continue ReadingKotlin 1.4 Released with a Focus on Quality and Performance

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

End of content

No more pages to load