Declarations in `when` statement

I would find it convenient to have an ability to declare a variable inside when statement, like follows:

when (something) {
    FIRST -> { ... }
    val a = someExpression //usable in below branches
    SECOND -> uses(a)
    else -> uses(a)
}

when statement branches are checked from top to bottom if they are not Java switch, right?
Even in Java switch, I think, it would be OK to copy the variable declaration into each of the following branches.

Current grammar just prohibits val inside when, so it won’t be a breaking change.

I don’t think it’s good to allow arbitrary code between branches, it would be too confusing.

However, even this may mess up the code readability pretty well when abused. Thoughts?
Has this been considered or is it planned?

No, this is not planned, and the semantics of this proposal seems fairly confusing to me. We do not always evaluate when branches sequentially, and it’s likely that future versions of Kotlin will use table-driven lookups in more cases than the current implementation, so copying the variable declaration into each branch would be the only way to implement it.

Then the question arises: what to do if a branch does not use the value of one of the variables defined above it? Do we copy the code of the initializer expression into the branch anyway, to ensure that the side effects of that expression still get evaluated? Or do we omit it, in order to reduce code size and improve performance, and lose the predictability? Also, can you refer to a in when conditions, and if you can, when does it actually get evaluated?

In other words, I’d be surprised if this is ever added into the language.

@yole, thanks for the explanation.

I agree that the semantics of such a feature is not quite intuitive and would have to be thoroughly designed and well documented.

From my point of view, the most sensible option for this concept is to think of when as of equivalent to if-else-if chain. Ok, copying the initialization into branches will surely mess the order of computation (side effects from the initializer will come after side effects from the condition check), so it’s not an option in cases when a condition check might have side effects.

Yes, now I see the performance degradation and the severe limitation for non-sequential when.

As to whether the variable evaluation may be omitted, from the above I would say no (just performing the line of the code seems most meaningful), but (complicating things even further) there might be a modifier to do so, though I don’t have a clear idea on that.

Piggybacking on this to say that being able to use it within when or to introduce bindings in the parens part of when would still be very very welcome: `it` within `when`

I wanted to add to this topic.

The table lookup semantic sorta makes sense, but the syntax kind of suggests it’s sequential. With table lookup, it’s kind of unclear what happens in this case:

when (x) {
  f() -> 'a'
  g() -> 'b'
}

Here, evaluating functions early with side effects would invalidate the optimization. It’s not super clear whether the table lookup optimization can be applied or not, from a pure syntactic point of view. Maybe adding an explicit annotation to restrict?

On the other hand, I think at least with the raw when statement, allowing assignment in the middle makes a lot of sense, like

when {
    a == b -> 10
    val x = 10
    x == 10 -> 20
    else -> 30
}

This simulates perfectly a lot of complicated if-else statements with assignments in the middle. The code with if-else will be really hard to read, with when+assignment, it looks so much cleaner.

To compare, the above code with if-else

if (a == b) {
    10
} else {
    val x = 10
    if (x == 10) {
        20
    } else {
        30
    }
}