Changes in Newer Kotlin Versions
Kotlin keeps changing.
Generally newer versions of Kotlin are backwards-compatible with older ones. So, when we switch to a newer version of Kotlin (say, in build.gradle
of an Android app project), most of our existing code should still work.
However, newer Kotlin versions offer new features that we can use in our development.
In this chapter, we will look at changes in the two newest Kotlin versions: 1.3 and 1.4.
Version 1.3
In November 2018, JetBrains released Kotlin 1.3. This was a relatively small update over Kotlin 1.2, but it did add a few new features of note. However, even today, some of those features are still marked as pre-release — not everything in a stable Kotlin version is stable.
With that in mind, here are some of the changes introduced in Kotlin 1.3.
when()
and Subject Variables
As we saw earlier in the book, you can use an expression in when()
to provide the value for comparison in each of the branches:
val thingy = "foo"
when (thingy) {
"foo" -> println("something")
"bar" -> println("something else")
else -> println("and now for something completely different")
}
Starting with Kotlin 1.3, you can make that expression also be stored in a local variable:
fun thingyProvider() = "like, whatever"
fun main() {
when (val thingy = thingyProvider()) {
"foo" -> println("something")
"bar" -> println("something else")
else -> println("we received: $thingy")
}
}
The variable’s scope is the when()
itself, so you can reference it from the branches but not anywhere else.
This is particularly useful for else
branches, such as for logging unexpected values.
JVM Interop for Interfaces
If you have a companion object
for an interface, you have improved interoperability options with Java:
- You can mark properties in the
companion object
with@JvmField
- You can mark functions in the
companion object
with@JvmStatic
In both cases, from Java’s standpoint, these become static
members of the interface.
So, suppose we had:
interface Something {
companion object {
@JvmField
val tag: String = "Something!"
@JvmStatic
fun printMe() {
println(tag)
}
}
// TODO add rest of interface
}
From Java code, we can reference Something.tag
and Something.printMe()
.
Inline Classes
Later in the book, we will explore inline functions. Simply put, a function marked with inline
works like a regular function, but the compiler “inlines” its implementation at each place it is used.
Kotlin 1.3 added a related capability, called inline classes. This feature is still deemed to be in alpha state, but it offers some interesting possibilities. We will explore inline classes more later in the book.
Contracts
Earlier in the book, we covered smartcasts, where Kotlin will allow syntax that on the surface seems impossible because it infers that it is possible under the circumstances.
open class Animal
class Frog : Animal() {
fun hop() = println("Hop!")
}
class Axolotl : Animal() {
fun swim() = println("Swish!")
}
fun main() {
val critter: Animal = Frog()
when (critter) {
is Frog -> critter.hop()
is Axolotl -> critter.swim()
}
}
Here, we can hop()
and swim()
on critter
because the compiler knows more about the type of critter
given the rules encoded in the when
branches.
However, prior to Kotlin 1.3, there were only a few places where smartcasts could help. Kotlin 1.3 adds a system of “contracts” that allows this sort of behavior in more places… including in code written by you (though this part is experimental).
Tactically, it means that if you have Kotlin 1.2 or older code, when you move to Kotlin 1.3, you may find that your IDE or linter will report a bunch of places where you can remove manual casts, unnecessary null
checks, and the like. These will reflect the contracts that were added to the Kotlin standard library.
Long-term, “custom contracts”, written by ordinary developers, will be an option. As noted above, this is considered experimental. This document outlines the approach.
Unsigned Integer Types
Kotlin 1.3 added support for unsigned numeric types, such as UInt
and ULong
.
Note, though, that these are still considered to be in beta form. Unless you have a specific reason to use them (e.g., simplify interoperability with some JNI code in Android), it is probably better to leave them alone for now.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.