DEV Community

Tomasz Wegrzanowski
Tomasz Wegrzanowski

Posted on

100 Languages Speedrun: Episode 05: Kotlin

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:

fun main() {
  println("Hello, World!")
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

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))
  }
}
Enter fullscreen mode Exit fullscreen mode

FizzBuzz

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

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))
  }
}
Enter fullscreen mode Exit fullscreen mode

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:

fun main() {
  println("Hello".length)
  println("Źółw".length)
  println("💩".length)
}
Enter fullscreen mode Exit fullscreen mode

It prints:

5
4
2
Enter fullscreen mode Exit fullscreen mode

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:

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()}")
}
Enter fullscreen mode Exit fullscreen mode

Which prints:

true
true
false
len of Point(x=30.0, y=40.0) is 50.0
Enter fullscreen mode Exit fullscreen mode

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 $_.

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 })
}
Enter fullscreen mode Exit fullscreen mode

It produces the expected:

[2, 4, 6, 8, 10]
[2, 4, 6, 8, 10]
[1, 3, 5]
15
Enter fullscreen mode Exit fullscreen mode

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.

Code for the Kotlin episode is available here.

Discussion (1)

Collapse
theonlytails profile image
TheOnlyTails • Edited on

One thing I would note is how Kotlin has a lot of features that make for very idiomatic code.
For example, here's how I would rewrite that Fibonacci function:

fun fib(n: Int) = if (n < 3) 1 else fib(n - 1) + fib(n - 2)
Enter fullscreen mode Exit fullscreen mode

Reading through this, it looks like an awesome series! This is really cool!