Why does new "when" syntax (in Kotlin 1.3M1) need the "val"?

I’ve read the blog about Kotlin 1.3M1 and its new features.
I noticed this new syntax:

fun Request.getBody() =
when (val response = executeRequest()) {
    is Success -> response.body
    is HttpError -> throw HttpException(response.status)
}

It’s a good feature. But I’m thinking that - why we need the modifier “val”?
After all, in “for” syntax, the indexing variable “i” has not such modifier:

for(i in 0..10){
    println(i);
}

why not just leave it alone without “val” like this ↓ ?

fun Request.getBody() =
when (response = executeRequest()) {
    is Success -> response.body
    is HttpError -> throw HttpException(response.status)
}

There is a discussion in the corresponding keep about it.
TL;DR:
x = foo() looks similar to an expression x == foo(). Also you are declaring a new variable.
But what about for you ask? for always declares a new variable. This is different to when where it is optional.

This is the argument I could find. I would have preferred it without the val keyword as well. But it’s definitely a step in the right direction.

1 Like

I don’t like the new syntax, because even with val it has the same readability problems as assignment expressions in other languages — the problems that Kotlin has been so good at avoiding!

So I’d like to suggest an alternative syntax:

fun Request.getBody() =
when (executeRequest()) as response {
    is Success -> response.body
    is HttpError -> throw HttpException(response.status)
}

Here the new variable is moved away from the expression, to avoid any confusion. And it reads much more like English. Plus, there’s a nice symmetry: the expression is on the left-hand side, and the new variable on the right, just as in the conditions below.

It’s not perfect, as as is normally used for casting, not assignment. But the when syntax is already special, and I think the greater readability would justify it.

5 Likes

The problem with as is that it means casting. It would be very confusing where using val x = has a very intuitive non-mistakable meaning. Assignment syntax is clearer to me, and if val is used to make clear that it introduces a new name, and to prevent comparison vs assignment issues that is fine.

7 Likes

Your example about the for-loop is potentially invalid. In for-loops, the declared variable is mutated between iterations. However the new syntax, explicitly says that the defined variable is immutable and is limited to the when scope

In for loops it rarely if ever makes sense to have no reference to the thing in the loop. Putting a val in there is just extra boiler plate (and technically a bit confusing since it’s not a single val, but several different vals over the course of the loop). For when statements, it is very often that you don’t want to assign the condition to any value. So not only does it make sense to explicitly state that you want the value to be stored, but the val CAN only be implied by checking to see if the condition is a valid assignment statement.

And even if you should probably be using

val a = if( x == y) 1 
        else 2

Rather than

val a = when( x == y) {
   true -> 1
   false -> 2
}

The latter is nonetheless valid and we don’t want to get into any = vs == territory.

End of the day there were a handful of different syntaxes proposed and a rather large discussion over it and this one was chosen.

In my opinion, this syntax is also not clear.

when (val response = executeRequest()) {
    is Success -> response.body
    is HttpError -> throw HttpException(response.status)
}

Such syntax as below can lead me to think that the assignment val response = executeRequest() can return something. But actually not, such syntax only works for when. Believe me, such rules can be very unfriendly for the beginners.

I’d like not to add this feature unless we have a better solution.