Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin when() local variable introduction

Let's say I have an expensive function called doHardThings() which may return various different types, and I would like to take action based on the returned type. In Scala, this is a common use of the match construct:

def hardThings() = doHardThings() match {
     case a: OneResult => // Do stuff with a
     case b: OtherResult => // Do stuff with b
}

I'm struggling to figure out how to do this cleanly in Kotlin without introducing a temporary variable for doHardThings():

fun hardThings() = when(doHardThings()) {
     is OneResult -> // Do stuff... with what?
     is OtherResult -> // Etc...
}

What is an idiomatic Kotlin pattern for this common use case?

like image 229
Yona Appletree Avatar asked Mar 29 '17 19:03

Yona Appletree


People also ask

How do you declare a local variable in Kotlin?

Local variables can be declared in two ways: first, with the val keyword, then they are immutable (the variable cannot be reassigned). If you are coming from Java, val would be equal to variables declared with a final keyword.

How do you initialize a variable in Kotlin?

Kotlin does not require you to mention the type of a variable when declaring it (thanks to type inference). A variable val must be initialized in the same block of code in which it was declared. You can define a variable as being able to contain a null value using the question mark ? .

What is .LET in Kotlin?

let takes the object it is invoked upon as the parameter and returns the result of the lambda expression. Kotlin let is a scoping function wherein the variables declared inside the expression cannot be used outside.

How do I declare a string variable in Kotlin?

To declare a string in Kotlin, we need to use double quotes(” “), single quotes are not allowed to define Strings.


1 Answers

Update: this is now possible, from Kotlin 1.3. Syntax is as follows:

fun hardThings() = when (val result = doHardThings()) {
     is OneResult -> // use result
     is OtherResult -> // use result some other way
}

Old answer:

I think you'll just have to have a block body for the function and save the result of the operation to a local variable. Admittedly, this is not as neat as the Scala version.

The intended use of when with is checks is to pass in a variable and then use that same variable inside your branches, because then if it passes a check, it gets smart cast to the type it was checked for and you can access its methods and properties easily.

fun hardThings() {
    val result = doHardThings()
    when(result) {
        is OneResult ->   // result smart cast to OneResult
        is OtherResult -> // result smart cast to OtherResult
    }
}

You could write some sort of wrapper around your operation somehow so that it only evaluates it once and otherwise returns the cached result, but it's probably not worth the complications that it introduces.

Another solution for creating the variable by @mfulton26 is to use let():

fun hardThings() = doHardThings().let {
    when(it) {
        is OneResult ->   // it smart cast to OneResult
        is OtherResult -> // it smart cast to OtherResult
    }
}
like image 167
zsmb13 Avatar answered Oct 18 '22 20:10

zsmb13