Hacker News

Hacker News

Show HN: A Kotlin compiler written in Go, 10x faster than kotlinc (github.com)
3 points by barteo •                         
barteo •                         
Hi HN, kc is a Kotlin compiler for the JVM, written in Go.

Why I built it: most Kotlin tools, like linters, KSP and the language server, are built on kotlinc's frontend, so they're only as fast as it is. A fast frontend could make room for:

- Linters that run in milliseconds instead of seconds

- A fast language server

- Much faster KSP annotation processing

- Quicker builds in CI, where every run starts a cold JVM

- Fast feedback for coding agents, which compile and fix code in a loop many times per task

I measured big gains in both speed and memory against kotlinc 2.4.21, running warm as in the Gradle daemon:

- kotlinx-coroutines-core: 2.50 s → 159 ms (16x)

- Ktor core modules: 2.32 s → 226 ms (10x)

- kotlinpoet: 1.23 s → 97 ms (13x)

- Memory: ~1 GB → ~100 MB

What it doesn't do yet:

- A few language features aren't supported

- No warnings, and only the errors that type checking finds, so some invalid code compiles

- JVM only, no Gradle plugin or IDE support

- Passes 95% of kotlinc's box tests

It's a prototype, but I plan to keep working on it until it's useful for a wide range of real projects.

Benchmark details and how to repeat them: https://github.com/barteo/kotlin-compiler-go/blob/main/docs/...

Rochus •                         
This is amazing, particularly the much smaller memory use, which I assumes comes because structured types can be used by value in Go (vs. the all heap approach of Java), isn't it? I assume the parallelization of the front-end is explicit in the source code (haven't looked at the source so far); what Go concepts did you use for it?

You could even consider re-using the Go compiler IR and backend for native, statically linked binaries, instead of generating JVM IR.

barteo •                         
Thanks!

Value types help: kc's type is a three-word struct stored inline in each node and compared with ==, while kotlinc's types are object graphs (type, lookup tag, attributes, argument array) built once for FIR and again for IR. I didn't measure how large impact it has overall though.

Yes, the parallelism is explicit, and it's plain Go: a pool of goroutines reading from a channel, used for parsing, checking and codegen. It's safe because all declarations and signatures are resolved first, one file after another.

A Go compiler IR is a very interesting idea, honestly, I haven't thought about that before.