Feature questions


#1

Hello!

I’m currently a University student in my second year and I’ve recently discovered functional programming. I learnt Scala and was really hyped up by the awesome features it had compared to Java, but I would like to learn Android app development in the following months. I also found Kotlin, which seems promising for Android (much lighter runtime library compared to Scala, faster compile-time, zero-overhead null safety, inlined functions and lambdas that lead to improved performance etc.), but I would have a few questions (for which I didn’t find answers searching on the web).

  1. What is the performance of Kotlin extension functions compared to Scala implicits? (I’m somewhat familiar with both concepts, but I don’t know the underlying implementations of either; I know, though, that Scala implicits can impose pretty big overhead if not used as value classes for a few restricted use-cases).
  2. Not sure about the current state for this feature, nor for the future state, but a frequent pattern in Scala is having a sealed trait / abstract class that is extended by case classes. Transposing this to Kotlin, it would be to have a sealed interface / abstract class extended by data classes. Right now, as far as I know, data classes cannot extend anything (to avoid breaking the equals function). However, I think this would be a good use case to allow data classes to extend a sealed interface / abstract class (it would be nice to have the compiler check exhaustiveness in when-expressions and still have automatic equals/hashCode/toString). Is this going to be implemented in the future?
  3. What is the consensus about proper pattern matching in when-expressions? Something like “when(x) { is v @ Tree(Tree(*, 5, *), 3, Leaf) -> println(v) … }”. Is it going to be implemented in a future version of Kotlin, or when-expressions will remain unchanged?
  4. The “yield” operator seems just too awesome to have it missing from Kotlin. What’s the status on this?

I am aware that the Kotlin development team is trying to ship a stable 1.0 release of the language and will not add new language constructs before that, but I’m curious whether these features are planned to be added in future releases.

I would really appreciate if anybody took the time to answer these questions. Thanks!


#2

1. Kotlin extension functions are compiled to regular static methods. Using extension functions does not incur any overhead. 2. The current restrictions on data classes are very likely to be relaxed after the release. We know that sealed data classes are a commonly requested feature, and we hope that we'll be able to support it. 3. As far as I can see, your example can be supported with Kotlin's existing 'when' expressions. There is no syntax for '*', but you can implement the Tree class in such a way that it will support storing wildcards in its nodes and will support comparing such nodes. 4. Different languages that support the 'yield' keyword have significantly different semantics for that, so it's not possible to answer that question.


#3

Thank you very much for your response!

When I was referring to the “yield” concept, what I meant was anything similar to “yield” from Python (which can make a for return a lazy iterator) to Scala (which can make for-expressions return a specific collection type). Considering the way Kotlin looks so far, I think “yield” in this context would be more suitable to return an iterator or an iterable (like in Python). So we could have something like this:

fun function(): Iterable<Int> /* Or maybe Iterator<Int> instead */ {
  for (i in 1…n)
          if (i % 2 == 1)
           yield i * i
}

I know for this particular example, the same can be achieved through map/filter/etc., but sometimes it allows greater expressive power, I believe.

Regarding the pattern matching, it is true that the same can be achieved with current when-expressions, but I think it’s a lot more complicated (I need a nesting level for every level of depth in the tree in which I want to pattern-match), whereas in other functional-like languages (such as Scala, Ocaml etc.), pattern matching on any depth can be achieved within the same expression. I think this:

when(x) {
  is Tree(Tree(*, 5, val v), 3, Leaf) -> println(v) // notice that v can also be captured as a variable and matches anything, like a wildcard
  // other cases here
}

looks a lot cleaner than this:

when {
  x is Tree && x.value == 3 && x.right == Leaf && x.left is Tree && x.left.value == 5 -> {
          val v = x.left.right
          println(v)
  }
  // other cases here
}

or this:

when {
  x is Tree && x.value == 3 && x.right == Leaf -> {
          val y = x.left
          if (y is Tree && y.value == 5) {
           val v = y.right
           println(v)
          }
  }
  // other cases here
}

I’m not sure if this type of pattern-matching can be implemented in the language (not sure how it would affect the grammar of the language, how hard it would be to parse etc.), but I think it would be a nice construct to have and was just wondering if improving the current when-expressions has ever been considered. I know Kotlin is not a purely functional language, but it has functional constructs and improved when-expressions don’t seem to be some alien-functional construct or something bad to have (especially since half of the construct is already implemented).

Again, I’m not sure if this can be implemented, nor that it must be, it’s just a nice construct I think would be nice to have and I was curious if it has ever been considered or if it is planned for future releases.

Thank you, once again, for your time!

Edit: corrected the syntax in when-expression examples, “when(x)” was replaced with “when”. Also corrected the generic parameter in the “yield” example.


#4

3. I think, Andrei asks, whether `when` construction is going to be as powerful as scala's `match`


#5

I for one would love the ability to at least bind a name in a when expression. Something like:

when (someComplexExpression) {
  null -> // …
  result -> // …
}

or if you’re tempted to counter that I should use ?: or other null things, then:

when (someComplexExpression) {
  0 -> // …
  1 -> // …
  n -> // …
}

It would also be great to be able to destructure data classes in when expressions as well, both to pattern match and bind names:

data Foo (n :Int, m :Int)


when (someFoo) {
  Foo(3, 3) -> // …
  Foo(3, m) -> // …
  Foo(n, m) -> // …
}

Pattern matching is certainly a feature that can become very complex, but binding names and destructuring data classes provide a lot of bang for their implementation complexity buck.