August 23, 2014

Using Kotlin from your Clojure projects

Or, introducing lein-kotlinc

Problem: You need to extends some Java interface or class to use some Java API, and for some reason Clojure’s java interop tools are too unwieldy to do it cleanly.

You could just write some Java. But, you don’t want to write Java because it’s 2014 and you’re too cool for that.

You could use Scala (possible with lein-scalac), but you don’t want to wait hours to compile anything and the language scares you.

If only you could use some language with the (relatively-speaking) fast compile times of Java, but more expressive, but also not so expressive that your boss gets confused and then angry because then you’ll just have to write it again in Java.

The solution? I have no idea, but Kotlin is pretty neat eh?

Why Kotlin?

  • Cleaner (inference) and safer (null-checking-wise, at least) than Java
  • Almost total Java interop, so you can do whatever you gotta do
  • Quality Russian engineering
  • Compiles faster than Scala; the Kotlin team’s goal is to match Java’s compile times, which is about as good as you’re going to do on the JVM.
  • Nice features you’ve come to expect from modern languages:
    • Closures
    • Type inference
    • Mixins
    • Some other stuff

To create a super-trivial example, here’s a small Kotlin class:

package testkotlinc


public class MyClass {
    public fun printString(s:String):Unit {
        System.out.println(s)
    }
}

Looks almost like Java, doesn’t it? Well, yes, it does, except for the different type declaration syntax, lack of semicolons, and the fun in there. Here’s something slightly more interesting:

package sparkquet

import parquet.column.ColumnReader
import parquet.filter.RecordFilter
import parquet.filter.ColumnRecordFilter
import parquet.filter.UnboundRecordFilter
import parquet.filter.ColumnPredicates

import sparkquet.Document

public class OnlyStuff : UnboundRecordFilter {
    public override fun bind(readers: Iterable<ColumnReader>?): RecordFilter? {
        val pred = ColumnPredicates.equalTo(Document.MyDocument.Category.STUFF)
        return ColumnRecordFilter.column("category", pred)?.bind(readers)
    }
}

You may recognize this from the thing I wrote about using Parquet with Spark, but in case you didn’t read it, the reason it exists was because the library demanded that I pass it the class object of a class implementing UnboundRecordFilter, which means I had to either do the :gen-class thing or make a Java version; I did the latter.

But I could have done it in Kotlin, and I would have benefitted from the automatic null checking. See those question marks in the code above? You can’t pass nullable things to Kotlin without flagging them as such, and you can’t call methods on nullable objects without using the “safe” ?. calling syntax, which checks for null and returns null if the caller is null. That’s handy!

How Kotlin?

Kotlin can be compiled to classfiles using the kotlin-jvm compiler, included in the kotlin-compiler package. Or, you can just use lein-kotlinc, which I whipped up last night to streamline this process. It’s very preliminary, but you can get up and running pretty quickly.

After your files are compiled, (lein kotlinc), you can use them just like Java classes:

(ns testkotlinc.core
  (:import testkotlinc.MyClass))

(defn -main []
  (doto (MyClass.)
    (.printString "Hello")
    (.printString "World")))

SUPER INTERESTING! Ok, perhaps not, but if you need to do something more complex with your non-clojure parts and maybe you don’t want to use Java because you’re a tragically naive hipster without the gumption to deal with nullable references and grumble grumble functions.

Let me know if you end up combining Kotlin and Clojure in some interesting ways, I’d love to hear all about it!