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!