Kotlin 1.4-M3 is Out: Standard Library Changes

Posted on by Pavel Semyonov

Today we’re glad to present the last milestone preview of Kotlin 1.4 – 1.4-M3. In this post, we’ll guide you through the changes this preview brings to the Kotlin standard library. Other components are also getting updates in M3; we’ll cover them soon in another blog post with the release candidate version (1.4-RC), which will finalize the scope of Kotlin 1.4.

The standard library changes in 1.4-M3 include:

You can find the complete list of changes in the change log. As always, we’re really grateful to our external contributors.

We would appreciate it very much if you could try the preview and share your feedback.

Standard library artifacts now include module-info descriptors

Starting from Java 9, you can modularize your application thanks to the Jigsaw project. The jlink tool allows you to generate a custom Java runtime image containing only the platform modules that are required for your app. You could use jlink with Kotlin standard library artifacts before, but you had to use separate artifacts for that – the ones with the “modular” classifier – and the whole setup wasn’t straightforward. The inability to include module descriptors in main artifacts was caused by issues with Android tooling, which have now been fixed.

Kotlin 1.4 adds module-info.java module information to default standard library artifacts, so you can use them with jlink with ease. In Android, make sure you use the Android Gradle plugin version 3.2 or higher, which can correctly process jars with module-info.

fun interfaces in the standard library

Kotlin 1.4 supports SAM conversions for Kotlin classes. You can mark an interface with only a single abstract method as a fun interface, and then pass a lambda as an argument when that interface is expected as a parameter. In the standard library, the following interfaces are now declared as fun interface‘s:

  • Comparator
  • ReadOnlyProperty
  • PropertyDelegateProvider (was introduced in 1.4-M2)

You can use a SAM-constructor that takes a lambda as a parameter to create an instance. The resulting code becomes much simpler:

Collection operations

  • A new sumOf function takes a selector function and returns a sum of its values on all elements of a collection. It is pretty similar to the existing sumBy and sumByDouble functions. The key difference is that the new sumOf function takes selectors with various return types, thus letting you handle sums of different types in the same way. Namely, sumOf produces sums of the types Int, Long, Double, UInt, ULong. On the JVM, BigInteger and BigDecimal are also available.
  • The min and max functions have been renamed to minOrNull and maxOrNull. Since their introduction in 1.0, min and max have returned null on empty collections. This contradicts the naming convention used across the Kotlin collections API: functions without the *OrNull suffix throw an exception if the receiver collection is empty. To get a null instead, you should use the *OrNull version of the function, for example, firstOrNull.
    Thus, we decided to gradually change the behavior of min and max. In 1.4-M3, we’re adding minOrNull and maxOrNull as synonyms for min and max and starting the deprecation cycle for min and max to reintroduce them with non-null return types.
  • We’ve introduced minOf and maxOf functions that return the minimum or the maximum value of the given selector function on the collection items. These functions cover the missing case for which it was required to write map { selector }.max()!! or maxBy { selector }!!.selector (or min and minBy).

    For consistency with the existing API, we also added minOfWith and maxOfWith, which take a Comparator as an argument.
    All four new functions follow the non-null convention we described above: they throw exceptions on empty collections and have *OrNull versions that return null in this case.

  • New overloads for flatMap and flatMapTo let you use transformations with return types that don’t match the receiver type, namely:

    • transformations to Sequence on Iterable, Array, and Map
    • transformations to Iterable on Sequence
  • A new flatMapIndexed function has been added as a counterpart for flatMap. As you may already know, Indexed in the name of a collection-processing function means that the operation applied has the element index as a parameter.

Common @Throws annotation

Although Kotlin doesn’t have checked exceptions, it uses the @Throws annotation for interoperability with languages that do have them, such as Java and Swift. Previously, there were separate annotations with this name for JVM (kotlin.jvm.Throws) and Native (kotlin.native.Throws).

Starting from 1.4-M3, the @Throws annotation is available as a part of the common library directly in the kotlin package (kotlin.Throws), which allows you to use it in the common code.

@Throws in suspending functions in Swift and Objective-C

In 1.4-M1, we announced changes in exception handling in Objective-C/Swift interop: now NSError is thrown only for exceptions that are instances of classes specified as parameters of @Throws annotation (or their subclasses). In 1.4-M2, we introduced basic support for Kotlin’s suspending functions in Swift and Objective-C. In 1.4-M3, there are small changes in the behavior of suspending functions annotated with @Throws :

  • If you have a suspend fun annotated with @Throws, you need to specify CancellationException::class as a parameter of the @Throws annotation. Otherwise, you will get a compilation error.
  • If there is no @Throws annotation on a suspend fun, it will implicitly use @Throws(CancellationException::class) when you call it from Swift.

Equality in floating-point arrays

Many of you know these handy extension functions for container types – contains, indexOf, and lastIndexOf. Some time ago, we figured out that their behavior on floating-point arrays (FloatArray and DoubleArray) may be controversial and can seem incorrect.
To be more specific, they use the IEEE 754 standard for floating-point arithmetics. This standard defines the following equality rules for corner cases:

  • NaN is not equal to NaN
  • -0.0 is equal to 0.0

Such rules may lead to unexpected results, for example:

Additionally, such behavior is inconsistent with how the same functions work on lists, because they use the total order equality:

In 1.4-M3, we start the deprecation cycle for the contains, indexOf, and lastIndexOf extension functions of FloatArray and DoubleArray. When trying to use them, you will see warnings with instructions for replacing the usages of these functions.
In future releases, we’ll tighten the deprecation level to ERROR and remove these functions from the public API.

Converting from KType to Java Type

In Kotlin 1.3.40, we added a useful typeOf function to the standard library. This function returns a runtime representation of the given reified type T as an instance of KType. However, in many practical use cases, you need to work with the Java reflection java.lang.reflect.Type objects rather than with KTypes. It was already possible to perform the necessary conversion, but this required using the full kotlin-reflect dependency. Now we’ve updated the standard library with a way to convert KType to Java Type – a KType.javaType extension property that returns Java Type:

Note that so far the obtained Java Type doesn’t behave correctly in some corner cases (like annotated type parameters or declaration-site variance), so KType.javaType stays experimental. You can find more details about the unsupported cases in this issue.

Compatibility

Note that Kotlin 1.4 is not backward-compatible with 1.3 in some corner cases. All such cases were carefully reviewed by the language committee and will be listed in the “compatibility guide” (similar to this one). For now, you can find this list in YouTrack.

Pre-release notes

Note that the backward compatibility guarantees do not cover pre-release versions. The features and the API can change in subsequent releases. When we reach a final RC, all binaries produced by pre-release versions will be outlawed by the compiler, and you will be required to recompile everything that was compiled by 1.4‑Mx.

How to try the latest features

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

In IntelliJ IDEA and Android Studio, you can update the Kotlin Plugin to version 1.4-M3. 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.

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

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

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

Share your feedback

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

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

Let’s Kotlin!

External contributions

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

Subscribe

Subscribe for updates