7

Is it possible to make the following code to compile in Kotlin?

val variable: String? = "string"

val (a, b) = variable?.run {
    1 to 2
}  
Diego Marin Santos
  • 1,923
  • 2
  • 15
  • 29

3 Answers3

14

The compiler does not allow destructuring because the expression on the right-hand side is typed as a nullable Pair<Int, Int>?, and it's unclear what values a and b should get in case variable is null.

To solve this, you need to get a not-null expression after =.

There's a lot of different ways to deal with nullable values and produce a not-null value from a nullable one, see: In Kotlin, what is the idiomatic way to deal with nullable values, referencing or converting them

For example, if you want to provide fallback values for a and b, then use the ?: operator as follows:

val (a, b) = variable?.run {
    1 to 2
} ?: (0 to 0)

An alternative, for example, would be to check variable for null first:

val (a, b) = checkNotNull(variable) { "variable should never be null" }.run {
    1 to 2
}
hotkey
  • 140,743
  • 39
  • 371
  • 326
5

Null doesn't have any destructuring declarations. If you want a value of null to destructure like it's a pair of nulls, you could add these extensions:

operator fun <T> Pair<T, *>?.component1() = this?.component1()
operator fun <T> Pair<*, T>?.component2() = this?.component2()

Otherwise, as the other answer shows, you need to provide a default using the Elvis operator.

It's not automatic because it doesn't know what you want. Depending on what you're doing with it, 0 to 0 may be most appropriate, or maybe -1 to -1 or 0 to null or null to null.

Tenfour04
  • 83,111
  • 11
  • 94
  • 154
  • There is the elvis operator if we would like to define a default value other than null. I think it would be reasonable to return `null to null`. – Diego Marin Santos Mar 04 '20 at 21:41
  • 1
    You could open an issue on YouTrack to suggest it. It's not a part of the stdlib. I suppose if there were a default, it would have to be `null to null` so it would work for any types. – Tenfour04 Mar 04 '20 at 21:57
1

The question is, what do you want to do if your variable is null? If you want to throw an exception, go with require or check as @hotkey suggested.

However I have the case where I just want to return if the value is null. So I wrote myself a little helper function that allows for this:

private inline fun <T> T?.exitIfNull(exitBlock: () -> Nothing): T {
    if (this == null)
        exitBlock()
    else
        return this
}

You can call this function as follows:

val (a, b) = variable?.run {
    1 to 2
}.exitIfNull {
    return
}

A nice little use of the Nothing keyword in Kotlin that I personally find quite fascinating

findusl
  • 2,454
  • 8
  • 32
  • 51