100 Languages Speedrun: Episode 05: Kotlin
Tags: java, kotlin
Published: 2021-11-24 19:31:17

Kotlin is to Java what ES6 is to old style JavaScript. A lot of people are stuck with JavaScript engine (like browser) or a JVM (like Android). Their native languages are atrocious, but using a completely non-native language leads to huge complexity interfacing with native APIs. And so compromise solutions were created, like ES6 for JavaScript, and Kotlin for Java. Kotlin is especially popular among Android developers, but you can use it anywhere where you can use JVM, and really it's hard to come up with a legitimate reason to use "plain Java" these days.

### Hello, World

We can start with the usual program! It's nothing unusual, unless you remember just how bad it was in plain Java:

```kotlin
fun main() {
  println("Hello, World!")
}
```

Unfortunately to run this we need to do this silly line, and the whole thing takes way too long for a reasonable hello world, 7s on my laptop:

```
$ kotlinc hello.kt -include-runtime -d hello.jar && java -jar hello.jar
```

Well, the Java world has very different expectations of what's a reasonable startup time than me. Kotlin has some sort of "scripting mode", and REPL, and it can be integrated with your IDE, so maybe it's not such a problem for people who code it on a daily basis.

I included a short script that allows `./run file.kt` in the code repository.

### Fibonacci

It's not too bad. We need some type annotations which feel like they should be inferable, but it's all perfectly reasonable code. If you think I'm asking for too much, just wait until we get to Crystal; but a lot of languages could figure out that `fib` is `Int` into `Int`.

Range loop syntax is perfectly readable, overall it's shockingly readable and concise code considering it's basically Java under the hood.

```kotlin
fun fib(n: Int): Int {
  if (n < 3) {
    return 1
  } else {
    return fib(n - 1) + fib(n - 2)
  }
}

fun main() {
  for (i in 1..30) {
    println(fib(i))
  }
}
```

### FizzBuzz

Kotlin threw away C style `switch` and instead introduced `when` syntax, which vaguely resembles Haskell style pattern matching.

```kotlin
fun fizzbuzz(n: Int): String {
  return when {
    n % 15 == 0 -> "FizzBuzz"
    n % 3 == 0 -> "Fizz"
    n % 5 == 0 -> "Buzz"
    else -> n.toString()
  }
}

fun main() {
  for (i in 1..100) {
    println(fizzbuzz(i))
  }
}
```

### Unicode

As Kotlin is basically Java under the hood, it still doesn't handle Unicode correctly outside the base plane, so the last answer is wrong:

```kotlin
fun main() {
  println("Hello".length)
  println("Źółw".length)
  println("💩".length)
}
```

It prints:

```
5
4
2
```

### Data classes

Java makes it really tedious to work with just about any kind of data. Every simple data class needs explicit constructor, getters, setters, hashcode, and equals. You cannot even use `==`, you need to run `.equals()`, but that would literally crash if one of the sides was null, so you need to null check both sides first, then `.equals()`. It's ridiculous amount of boilerplate for basic data manipulation.

Kotlin avoids almost all of this bullshit:

```kotlin
data class Point(val x: Double, val y: Double) {
  fun length() = Math.sqrt(x * x + y * y)
}

fun main() {
  val a = listOf(1, 2, 3)
  val b = listOf(1, 2, 3)
  val c = Point(30.0, 40.0)
  val d = Point(30.0, 40.0)

  println(a == b)
  println(c == d)
  println(null == d)
  println("len of ${c} is ${c.length()}")
}
```

Which prints:

```kotlin
true
true
false
len of Point(x=30.0, y=40.0) is 50.0
```

Well, we still needed to do `listOf(1, 2, 3)` instead of `[1, 2, 3]`, and it would complain if we tried `Point(30, 40)`, but it's not too bad.

### Functional programming

And how would we do `map`, `filter`, and `reduce` in Kotlin? It looks almost like Ruby with `{ arguments -> ... }` blocks. Interestingly if you pass a block without any arguments, it treats as if it had default `{ it -> ... }`. That's a rare feature, most notably seen in Perl where it's called somewhat more cryptic `$_`.

```kotlin
fun main() {
  val alist = listOf(1, 2, 3, 4, 5)

  println(alist.map{ x -> x * 2 })
  println(alist.map{ it * 2 })
  println(alist.filter{ it % 2 == 1 })
  println(alist.reduce{ a, b -> a + b })
}
```

It produces the expected:

```
[2, 4, 6, 8, 10]
[2, 4, 6, 8, 10]
[1, 3, 5]
15
```

### Should you use Java?

Normally I'd ask "should you use Kotlin", but that's looking at things backwards. The real question is "should you use Java" and the answer is clear and unambiguous NO! If you need to run something on JVM and interact with the "Java" ecosystem, you can do this without ever touching that miserable excuse for a language. Kotlin is to Java what ES6 was to old style JavaScript, but the improvement is much greater here. Old style JavaScript is dead, completely replaced by ES6+ JavaScript, and that's the fate that should befall Java as well.

There are other JVM languages like JRuby, Clojure, Scala, and so on, but they are essentially different languages, with different semantics, and with varied interoperability story. Kotlin is just Fixed Java, nothing more, nothing less.

So please don't use Java, ever.

### Code

[All code examples for the series will be in this repository](https://github.com/taw/100-languages-speedrun).

[Code for the Kotlin episode is available here](https://github.com/taw/100-languages-speedrun/tree/master/episode-05-kotlin).