X
Popular Searches

What’s New In Kotlin 1.6?

Photo showing Kotlin logo overlay on computer code
Trismegist san/Shutterstock.com

Kotlin 1.6 is out with new features, an improved experimental memory manager, and an enhanced standard library. The additions help mature JetBrains’ increasingly popular cross-platform and cross-discipline language.

New Native Memory Manager

Arguably the biggest change for the Kotlin ecosystem is the arrival of the new memory manager for Kotlin Native. While it’s still labelled as a developer preview, the updated manager is representative of the direction Kotlin will take in the future.

The revised design is better equipped to deal with the different compilation backends used to transform Kotlin into native platform code for iOS and Android. Sometimes the platforms require different optimizations for a specific operation. The current approach imposes limitations on concurrency and can create memory leaks without special developer attention.

The next generation memory manager addresses these shortcomings. It offers leak-free primitives for concurrent operations that are safe to use as-is. The changes also bring Native memory management into greater parity with the existing memory manager for JVM development.

While the new system is available in Kotlin 1.6, it’s not currently intended for production use. In some situations, performance could be reduced by up to 5x compared with the legacy memory manager. Development efforts are ongoing on a performant version that’s ready for general uptake.

Sealed When Statements

Sealed when statements let you receive a compiler warning when you forget to handle a possible case. If you pass a sealed class, boolean type, or enum into a when, you’ll normally want to take an explicit course of action for each possible input value:

sealed class Drivetrain {
    data class Electric(val Power: Int) : Drivetrain()
    data class Diesel(val Power: Int) : Drivetrain()
    data class Hybrid(val Diesel: Drivetrain, val Electric: Drivetrain) : Drivetrain()
}
 
fun getTotalPowerKwh(drivetrain: DriveTrain) : Int {
    when (drivetrain) {
        is Drivetrain.Diesel -> drivetrain.Diesel.Power
        is Drivetrain.Electric -> drivetrain.Electric.Power
    }
}
Advertisement

In the example above, the Drivetrain sealed class has three data classes within it. The when statement only handles two of them – if your code receives a hybrid drivetrain, an incorrect value will be returned.

The Kotlin compiler will now alert you to this problem. In Kotlin 1.7, not exhaustively covering all the possibilities will result in a compilation error.

Suspending Type Transformations

Transformations from regular to suspending types have been stabilized via automatic compiler conversions. The compiler will create the conversion automatically when you pass a regular type expression into a context where a suspending type is expected.

This enables code like the following:

fun createUser(name: String) {
    // ...
}
 
flow.collect(::createUser)
 
val createUserFunction = ::createUser
flow.collect(createUserFunction)

This code used to break on the second flow.collect() call. The createUserFunction variable refers to the regular function definition, not the suspension created by the first call. Kotlin will now handle this by creating a suspended version when the receiving context requires it.

Suspending functions are also supported as supertypes now. This lets you pass classes that implement suspending functional types wherever a suspending function reference is currently supported.

class ImplementsSuspendingFunctionalType : suspend () -> Unit {
    override suspend fun invoke() { /* ... */ }
}
Advertisement

The suspend () -> Unit interface is implemented in the same way as you can already use () -> Unit for non-suspending types.

Code Coverage Scanner

Kotlin now has an official code coverage scanning tool. Kover is a Gradle plugin which collects the coverage statistics of tests for Kotlin JVM, Multiplatform and mixed Java projects. It can generate reports in HTML and XML formats.

Kover provides full compatibility with the Kotlin language and its Gradle toolchain. Although some third-party tools can already provide coverage scores, they exist outside the ecosystem and don’t always have visibility into every task. Kover offers a fully integrated approach. Development is ongoing with this initial release labelled as experimental.

To enable Kover, add the following lines to your top-level build file:

plugins {
     id("org.jetbrains.kotlinx.kover") version "0.4.2"
}

Kover will now run as part of your Gradle builds.

Standard Library Additions

There are a few noteworthy changes to the standard library, including the promotion of several beta functions to stable:

readln() and readlnOrNull()

These two new functions read and return a line from the standard input stream. The former will throw if the EOF mark has been reached whereas the latter returns null.

typeOf()

The typeOf() function lets you determine the actual type of a reified type, usually expressed as T, at runtime.

inline fun <reified T> getTypeString() : String {
    val type = typeOf<T>()
    return type.toString()
}

Collection Builders

New builder functions let you easily create collections from a set of different values. You can combine maps, lists, and sets into new collections using first-class functions:

val fruits = listOf("apple", "banana");
val veg = listOf("carrot", "cabbage");
 
val groceries = buildList {
    add("milk")
    addAll(fruits)
    addAll(veg)
}
 
// ["milk", "apple", "banana", "carrot", "cabbage"]

Duration Values

The Duration class for representing time values has been promoted to stable. It provides an integrated type to store a time period duration in your code. The class has methods that facilitate easy conversions between units:

// Emits 1.0
println(60.toDuration(DurationUnit.SECONDS).inMinutes);

More Standard Library Changes

Integers have new rotateLeft() and rotateRight() functions. These rotate the number’s binary representation by a specified number of bits in the indicated directions. Regexes gain sequence split functions and consistent behavior for replace() and replaceFirst() across Java and JavaScript environments.

Some existing functions have been deprecated. The concat(), match(), and matches() functions on strings, as well as the sort() function on arrays, will now issue warnings. Their functionality is already covered by alternative options.

Other Changes

Kotlin 1.6 adds a few ecosystem enhancements and quality-of-life improvements. Among these is support for Xcode 13 and the ability to compile Windows builds on any platform. If you’re targeting mingwX64 or mingwX86 for Windows, you can now compile from any system that supports Kotlin/Native development.

Advertisement

Improvements to compiler caches for Linux and iOS builds have halved typical build times after the first run. Updates to the Kotlin dependency chain significantly reduce disk usage. Switching to LLVM 11.1 has cut the macOS version from 1200 MB to around 300 MB.

If you’re using Kotlin JavaScript, you can now disable automatic downloads of Node.js and Yarn during the build process. This is useful when you’re compiling code in a preconfigured environment where the host already has these dependencies installed.

Summary

Kotlin 1.6 is a healthy release with new experimental features paving the way forwards and a good roster of language and standard library changes that you can use today. There have also been improvements to interoperability between Kotlin flavors so more code will behave the same whether it’s compiled for JVM, Native, or JavaScript.

The 1.6 milestone also sees Kotlin’s maintainers offer an extended support period for older API versions. Three previous versions will now be supported on a rolling cadence. This means you can currently choose to develop against Kotlin versions 1.3 to 1.6, giving you more time to upgrade between releases.

You can move to Kotlin 1.6 today by updating your version of IntelliJ IDEA, Android Studio, Xcode, or the Kotlin CLI compiler. It’s worth reviewing the compatibility guide first to make sure you’ve addressed all the previously reported deprecations that will throw warnings or errors in 1.6.

James Walker James Walker
James Walker is a CloudSavvy IT contributor. He's the Founder of Heron Web where he provides bespoke software development services to SMEs, specializing in web applications and APIs. He's experienced with the complete development lifecycle and works with DevOps technologies such as GitLab, Docker, and Kubernetes. Read Full Bio »

The above article may contain affiliate links, which help support CloudSavvy IT.