How to pattern match optionals in Kotlin?
Asked Answered
H

4

19

Is it possible to write something like this, or do we have to revert back to manual null checking in Kotlin?

val meaningOfLife : String? = null

when meaningOfLife {
    exists -> println(meaningOfLife)
    else   -> println("There's no meaning")
}
Hower answered 3/6, 2016 at 9:24 Comment(6)
the if construct is more preferable for binary situations like this one. Has the exact same effect as when hereSurinam
Why is it preferrable if it has the same effect? The advantage of when is that it has room to grow.Hower
In case of nullability when has nothing to grow for. Using when as a glorified if is quite wasteful IMOSurinam
It's only wasteful if when desugars to something that uses more resources than a plain if. If not, then you have one less line and conditional expandability in contrast to if.Hower
When I see when, I prepare myself to a multy-chose. So it would surprised me to find only a bi-chose.Surinam
It is only a matter of taste. Fortunately Kotlin allows us to do what we think is necessarySurinam
G
20

One of possible ways is to match null first so that in else branch the String? is implicitly converted to String:

val meaningOfLife: String? = null

when (meaningOfLife) {
    null -> println("There's no meaning")
    else -> println(meaningOfLife.toUpperCase()) //non-nullable here
}

This is a special case of a smart cast performed by the compiler.

Similar effect can be achieved with is String and else branches -- is String-check is true when the value is not null.

For more idioms regarding null-safety please see this answer.

Gilly answered 3/6, 2016 at 15:15 Comment(5)
Making is String the first case achieves a similar effect.Viridescent
@EPadronU, not completely: as seen from bytecode perspective, is String causes instanceof check, while the code in the answer doesn't, it only compares the reference with null.Gilly
Thank you. That's very useful to know. Fortunately, I said "similar" ;)Viridescent
Unfortunately the smart cast only works if meaningOfLife is immutable. There's no way around meaningOfLife!!.function() when it's mutable, is it?Hower
@TomTom, the compiler cannot guarantee null-safety in case of var, so there's indeed no other way but to create another local val. But when a variable is non-nullable and you only need smart cast for var you can write something like myVar.let { when (it) { /*smart cast works here*/ } }.Gilly
V
13

You can accomplish that as follows:

val meaningOfLife: String? = null

when (meaningOfLife) {
  is String -> println(meaningOfLife)
  else -> println("There's no meaning")
}
Viridescent answered 3/6, 2016 at 9:31 Comment(0)
S
2

FYI, the particular situation in the question has a way simple solution with the ?: operator of default value:

println(meaningOfLife ?: "There's no meaning")

The example in the question is probably a simplified real situation, so a null check is how I would do it. IMHO if is a better way to go when you have a binary chose of control flow:

if(meaningOfLife != null)
    println(meaningOfLife)
else
    println("There's no meaning")

Takes exactly the same number of lines, BTW.

Surinam answered 4/6, 2016 at 5:57 Comment(1)
I understand the question was probably not about it, but I think this option should also be mentionedSurinam
V
0

Try this:

val meaningOfLife : String? = null    
meaningOfLife?.let { println(it) } ?: println("There's no meaning")

let in stdlib

Variolite answered 3/6, 2016 at 9:35 Comment(1)
OP wanted to know how to use pattern matching to do it. Anyways, I think your expression could be cleaned up to this: println(meaningOfLife ?: "There is no meaning")Curb

© 2022 - 2025 — McMap. All rights reserved.