Make using when-keyword more concise (or provide alternative)


#1

The following looks like only a small thing as it saves only one line, but it is continuously bothering me.

If you want to process a result of an expression using the when-keyword, Kotlin isn’t as concise as I love it from Scala. That’s due to the fact, that I always need some kind of value to reference inside the case block:

val shape = getShape()
val area = when (shape) {
  is Circle -> Pi * shape.radius * shape.radius
  is Rect -> shape.width * shape.height
}

Even leaving full pattern matching out of the game here (though I really miss it), I could write the following in Scala:

val area = getShape() match {
  case circle: Circle => Pi * circle.radius * circle.radius
  case rect: Rect => rect.width * rect.height
}

It’s only one line less, but the fact that in scala the whole stuff is written as one (match) block makes it much more readable in a larger context. In contrast in Kotlin I find myself regularly extracting things like shown above into their own functions.


#2

Of the many who tried to argue this point I have to say that I like your approach for naming the variable. It is elegant although i don’t know whether it will not interfere with other aspects of when selectors.


#3

This is how you do it in Scala :slight_smile: I really miss full pattern matching from Scala as well.


#4

I confess, I was going to be all cocky like “What about…”, but the (IMHO) idiomatic Kotlin version of this is actually a line LONGER:

val area = with(getShape()) {
   when (this) {
       is Circle -> Pi * radius * radius
       is Rect -> width * height
   }
}

…although it does have the nice side benefit of eliminating the temp variable entirely.


#5

Well, I could certainly see something like this being added to the language :

val area = when (val shape = getShape()) {
    is Circle -> Pi * shape.radius * shape.radius
    is Rect -> shape.width * shape.height
}

as this was discussed at length in this thread and is proving popular with voters.


#7

Thanks for the hint: Though it adds an extra level of indentation, that’s definitely better than the extra variable. I don’t really like the this context here, but as I’ve learned I can also use:

val area = getShape().let {
  when (it) {
    is Circle -> Pi * it.radius * it.radius
    is Rect -> it.width * it.height
  }
}

#8

That looks like a good workaround. Though I still more like that match in Scala works as some kind of binary operator allowing me to add it to the end of a complex expression rather than to the beginning with the complex expression in parenthesis.

Nevertheless your suggestion would fix my main concern and thus I’ve also voted for the ticket.

In general I really would like to see pattern matching in Kotlin. It’s the thing I miss most coming from Scala. I have created an event-sourced Akka-Play application some time ago and most of the code consisted of match blocks. It was one of the best readable codes I’ve ever dealt with. I can live without Scala’s implicit stuff, I can (mostly) live without partial functions but missing pattern matching is really a step backward. (Besides this I want do admit that the Kotlin team has done a great job!)

BTW: Sorry for opening a new thread instead of contributing to the one you’ve linked to. But searching for “when” unfortunately wasn’t very helpful… :wink:


#9

The alternative I proposed was to allow the use of it:

val area = when (getShape()) {
  it is Circle -> Pi * it.radius * it.radius
  it is Rect -> it.width * it.height
}

#10

Whilst it would be nice if ‘it’ could be used, you would have the problem that, if there are any lambdas in scope which take a single unnamed parameter, then ‘it’ could be confused with that parameter.