Destructuring in when

Nothing specific. Think I heard it in one or more talks on Kotlin that implicits and pattern matching were deemed complex and they avoided them.

Pattern matching is one the best things about Scala, and it’s something that’s easy to understand while being extremely useful. Sometimes I think people think all features of Scala are over complex functional programming idioms. While there are features that maybe fit into that category, pattern matching is not one of them. When I re-wrote a Scala library in Kotlin, the lack of pattern matching was the biggest annoyance to me.

9 Likes

What are the key differences between pattern matching and the when expression?

In pattern matching you can a) match against values inside a structure (hence the term) and b) extract values from the matched expression.

So if we had a data class called Person, we could do

when(person) {
  Person("sam", age) -> println("This matches all sams and makes $age available as a parameter")
  Person(name, _) -> println("This matches all persons, and makes $name a parameter and ignores the age")
}

and various combinations of that kind of thing.

In Scala if you use a literal, then it will be matched against that value, if you use a variable name it will extract the value and assign it to the variable, and if you use a variable name inside backticks it will match against the value of an already defined variable (but that variable must be ‘constant’).

6 Likes

I’ve been using Kotlin and Rust side by side for a while now, and have really missed proper pattern matching from Rust, while missing proper IDE support from Kotlin :slight_smile:

4 Likes

To not create temprorary objects, I propose following syntax:

when (obj) {
    is Pair<*, *> -> when((k, v) *obj) {
        (1, "5") -> ... //  k, v available here
        ("asdfa", true) -> ...
        (variable, _) -> ...
    }
}

if ((k, v) *obj == ("asdfa", 42) {
    // k, v available here
}

and would be nice to see matched value as it

when (obj) {
    is Pair<*, *> -> when((k, v) *obj) {
        (1, "5") -> it::run { println("[$key=$value]") }
    }
}

with => arrow to make it available as this

(1, "adfa") => println("[$key=$value]")

Some very preliminary (and interesting) discussion from Brian Goetz on pattern matching in Java.

http://cr.openjdk.java.net/~briangoetz/amber/pattern-match.html

I don think that full blown pattern matching would be absolutely necessary. When can already do a lot of powerful things. What I’d like to see especially is something like this

when(thing) {
    is Pair(a, b) -> { }
    is OtherDataClass(a, _, c) -> {}
}

In that case, all that’d need to do is desugar it to a traditional data class destructuring.

when(thing) {
    is Pair -> {
        val (a, b) = thing
    }

    is OtherDataClass -> {
        val (a, _, c) = thing
    }
}

Would make that sort of code look much nicer, imo.

5 Likes

Hi,
Another useful usage would be the collection deconstruction:

 when (coll) {
                (first, second, third) -> // do smth with the first 3 elements
                else -> // do something else 
    }

The above first case would correspond to having a collection with at least 3 elements.
In scala ::Nil helps to restrict the case to exactly 3 elements

I really miss this feature from Haskell & Scala. I hate introducing local vals just for the purpose of referring to them in when branches.

9 Likes

Having something like but not really pattern matching feels so off to me, especially in the presence of sealed and data classes. I couldn’t believe it and kept searching for what I was doing wrong. Finding out that it’s just not there in Kotlin was a big disappointment; the advantages of pattern matching in terms of explicit brevity are so big that its lack is noticeable.

I keep comparing Kotlin to Swift, and Swift has pattern matching for enums with associated values (which are really ADTs). The Scala approach to implementing it on top of the JVM seems prudent to me.

I’d appreciate some clarification about what was deemed “too complex”. The implementation in the compiler? The language feature for programmers?

I shifted some things around in my head and in a scratch, and I think pattern matching could be an additive, mostly-sugar extension. That is, programmers wouldn’t have to deal with it unless they want to, and huge parts of the implementation beyond desugarisation might be covered by the existing compiler. I’m sure I’m missing things, but I don’t understand why this is apparently not a discussion worth having.

5 Likes

I share exactly the same thoughts, and I’m also coming from a Swift background.
If programming complexity is an issue, Swift being open source, compiler programmers could take a glance at what was done in Swift :smile:

1 Like

I often talk of Kotlin with a Scala developper and the lack of pattern matching is a major issue for him.

He is probably not the only scala dev in that case.

1 Like

Here is the JEP for pattern matching in Java
http://openjdk.java.net/jeps/305

If Java is proposing to add it, then it’s got to at least be on the radar for Kotlin, lest Kotlin be left behind.

1 Like

It will take many years till it is fully introduced in Java. They plan to introduce it in small steps. The first one being switch expressions.

Of course, it will take a long time. Point is, its on the roadmap.

2 Likes

Yes, please, I miss pattern matching. +1 to what sksamuel and marikka said above.

IMO, destructuring is one of those “Aha!” moments in programming that is hard to do without once you’ve gotten used to it. And several other languages do have programmers getting used to it. So true matching would be awesome, but even if it were only allowed to go one level deep, binding names to parts would really improve the ergonomics of when usage.

5 Likes

+1 to everything here. I think with java tentatively targeting JDK 15 for pattern matching preview that we should revisit this. I have had many occasions where destructuring a Pair or Triple would be useful:

when(Pair(int1, int2)) {
(1, ) -> something()
(0, _ ) -> somethingElse()
(
, 5) -> anotherThing()
}
This is clearly contrived but these scenarios pop up and the alternative (nested whens) are much less powerful and more verbose and error prone. It would be a massive boon to how expressive the language is and help motivate other teams in my organization to consider kotlin.

2 Likes

I suppose JetBrains could somehow make the compiler understand pattern matching in a way that compilation would only take longer if the source code contained pattern matching logic.

It would also be nice to have some statistics on how longer a big code base using pattern matching would take to compile, compared to a similar code base without it.

With all that, developers could then decide whether they wanted to sacrifice compilation time for some more development comfort with pattern matching.

One important feature of FP languages is full blown support for pattern matching. Kotlin must learn from Scala in this case and provide pattern matching support. Java 15 anyways is coming with Pattern matching support. So, its time to revisit this.

1 Like