Experience porting a Java8 library (functional lists, lazy lists) to Kotlin


#1

I thought some people here might find this valuable / entertaining / challenging.

I teach a sophomore CS class at Rice University (http://comp215.blogs.rice.edu/) which introduces Java8 and does everything in a functional style. For fun, I decided to try porting some of the basics of my functional list support library to Kotlin. I’ve posted the results on GitHub and I thought I’d list my obervations for everybody here to chew on.

https://github.com/danwallach/K215-Export

You can see all of my notes here:

https://github.com/danwallach/K215-Export/blob/master/java-vs-kotlin-notes.txt

In a nutshell, I really enjoyed playing with Kotlin. The ability to write extension functions, in particular, really cleans up the mess that I had to do in Java8 to write the same things, plus the fact that you have “real” lambdas means that you have to spend a whole lot less time worrying about <in T> vs. <out T> than you do in Java8, since you don’t need to declare anything awful like Function<? super T, ? extends T> when all you want is (T)->T. I also enjoyed taking everything that I’d previously done with Java8’s Optional type and redoing it with Kotlin’s more precise handling of null than you’d ever get away with in Java (at least, not without tons of annotations or a static checker).

There are a bunch of places where Kotlin is still showing its beta-ness. In particular, if you want to have a singleton generic empty-list, in Java you would take advantage of @SurpressWarnings(“unchecked”) and Java’s type erasure to let you have one instance of the empty-list for all types. I transliterated this concept to Kotlin and it gives some scary warnings (“This cast can never succeed”), but in fact they succeed just fine.

This code isn’t something I intend anybody to adopt yet. It’s just my first crack at writing something non-trivial in Kotlin. I’d appreciate feedback from people here about whether this code is written “properly” for Kotlin and/or how it could be tweaked to compile without any warning messages.


#2

From your java-vs-kotlin-notes.txt:

  • Curly braces and return values can mix in odd ways:
    fun foo() = 3 // function that returns the number 3
    fun foo() { 3 } // returns nothing
    fun foo() { return 3 } returns 3 again

This surprises me.

I would have assumed that for

fun foo() {3}

that since 3 is the last expression that it would be returned.

Why is nothing returned?

Neil


#3

Here’s the confusion: when you’re defining a function with curly braces, you’ve created a “block” of code, and blocks must explicitly use the return keyword. However, lambdas also use curly braces, and when you’re defining a lambda, you don’t need the explicit return keyword. So you’ve got two things that are syntactically similar, but with notably different meanings.

I think this confusion is driven by the language’s use of “non-local returns”, (see also function literals vs. function expressions) which you have to read carefully to understand.

If you’re coming from Java or C, then this non-local return stuff is something that you’re likely to want on occasion. If you’re coming from other functional languages, you might prefer to live in a world where “everything is an expression with a value”. You can get there by avoiding function declarations with curly braces and always instead using the fun foo() = 3 style.

Incidentally, when I was first playing around with Kotlin, I was sometimes generating my lambdas incorrectly and writing malformed code like so: { x, y -> { blah blah } }, which was my mistranslation of Java8 lambda syntax to Kotlin. (The proper form in Java8:(x,y) -> { blah blah } and the proper form in Kotlin: { x, y -> blah blah }.) That might be worth adding a warning into the IDE.