Version 1.4

August 2020 brought us Kotlin 1.4, which has a longer roster of developer-facing changes, though they are of mixed importance. This section examines some that may be encountered more often by ordinary Kotlin developers.

Exception Changes

One change that might cause you to need adjustments to your code is in how Kotlin raises null pointer exceptions in Kotlin/JVM, including in Android apps.

Formerly, a null pointer resulted in any number of possible exceptions, including:

…in addition to Java’s NullPointerException.

In Kotlin 1.4, Kotlin now reliably generates a NullPointerException in all cases.

Probably you do not have code that depends on the particular type of one of these exceptions. That is because usually we do not explicitly worry about this exception compared to others. But, if you had a try/catch that depended upon a null pointer being raised as one of the former exception types, that code will need to be adjusted.

Trailing Commas

We have a lot of comma-delimited things in Kotlin, particularly all of our parameter lists:

val spices = mutableListOf("Ginger", "Posh", "Scary", "Sporty", "Baby")

Now, we can have trailing commas, without causing a syntax error. This is handy when the entries are all on individual lines, particularly for copying and pasting:

val spices = mutableListOf(
  "Ginger",
  "Posh",
  "Scary",
  "Sporty",
  "Baby",
  "Pumpkin",
)

The trailing comma is ignored by the language parser.

Mixed Named and Positional Parameters

It used to be that named parameters could only come at the end of a call:

doSomething(2, 4, 6, 8, whoDoWeAppreciate = "everyone!")

The idea was that named parameters mostly would be used for optional parameters, where the function had declared default values.

However, a secondary use of named parameters is simply for documentation. For that, Kotlin 1.4 now supports named parameters in arbitrary spots:

fun doSomething(
  colors: Int,
  sides: Int,
  quantity: Int,
  theseParametersAreNotSerious: Int,
  whoDoWeAppreciate: String = ""
)

doSomething(2, sides = 4, quantity = 6, 8, whoDoWeAppreciate = "everyone!")

Basically, up through the last positional parameter, the names are purely documentation — the position of the parameter is what matters.

Functional Interfaces

Earlier in the book, we saw SAM, the Single Abstract Method pattern. It takes code like this:

val thingy = object : SomeJavaInterface {
  override fun beUseful(value: String) {
    println(value)
  }
}

…and shrinks it down to code like this:

val thingy = SomeJavaInterface { println(it) }

However, this was limited to interfaces that had a single abstract method (e.g., beUseful()). And, this was limited to Java interfaces — Kotlin interfaces with a single abstract method did not support the SAM usage pattern.

Kotlin 1.4 relaxes that a bit. You can use SAM syntax with a Kotlin interface… if that interface is fun:

fun interface Comparitizer<T> {
  fun valid(item: T): Boolean
}

fun <T> firstItemOrNull(items: Collection<T>, comparitizer: Comparitizer<T>): T? {
  items.forEach {
    if (comparitizer.valid(it)) return it
  }
  
  return null
}

data class Event(val id: Int)

fun main() {
  val events = listOf(Event(1), Event(5), Event(1337), Event(24601), Event(42), Event(-6))

  val leetEvent = firstItemOrNull(events, Comparitizer { it.id == 1337 })

  println(leetEvent)
}

Marking the interface itself with the fun keyword makes it a “functional interface”, one that supports SAM syntax. However, a functional interface imposes one key limit: there can only be one abstract function (a.k.a., single abstract method). The fun interface can have as many concrete functions as are needed, though.

Delegated Properties Modifications

Kotlin 1.4 added a new feature to property delegates: the ability delegate a property to another property. We will explore that later in the book.

Explicit API Mode

For those of you considering publishing a Kotlin library, Kotlin 1.4 adds what JetBrains calls “explicit API mode”. You can opt into this for a library module or project. It adds additional compiler checks to help ensure that your public API is what you think it is. Quoting the proposal that led to this:

Compilation in such mode differs from the default mode in the following aspects:

  • Compiler requires you to specify explicit visibility for a declaration when leaving default visibility would result in exposing that declaration to the public API.
  • Compiler requires you to specify the explicit type of property/function when it is exposed to the public/published API.
  • Compiler requires you to explicitly propagate experimental status for functions which contain experimental types in the signature.
  • Compiler warns you when declaration exposed to public API does not have a KDoc.

The documentation has additional details, such as how to enable this mode.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.