6 months of kotlin

kotlin logo

I have now worked with kotlin for a bit more than half a year and thought it was about time to write down some insights. So far I have worked profesionally with Java, JavaScript, Ruby, Go, Groovy, Elm and Python to give you some context of my previoous experiences. I have worked quite a lot in tha Java space so that is what I know most about. My last job howver was with Python mostly so it actually been 5 years since I touched the JVM last. My experience now is from backend work built with spring and serving an android app.

Main takeaways

Kotlin is a better Java. It invites to functional style although all the OO legacy of Java is still around. Many Kotlin features are slowly making their way into Java. It’s a feeder team for Java.

Kotlin runs on the JVM. The pros of this are obviously access to the vast ecosystem of Java. Using a framework like Spring boot is easy and comes with almost no hassle. The cons are just as obviously. The Java ecosystem is quite bloated and turnaround times for feedback loops are typically quite slow.

My top five features

Functions on one line.

It is possible to define a function without curly braces but then it needs to be one statement. If it is short enough it fits on one line.

fun square(Int: x): Int = x * x

This is nice. The downside is that you can spread your statement over several lines and do some function chaining to avoid the curly braces. This seems to be idiomatic in Kotlin but is sometimes not that readable. (Easy to fix though with a bunch of shorter functions.)

Parallelism

We haven’t used it yet in the code base I hang out in now. But it looks really neat as compared to this in Java. There are all kinds of async possibilities and also channels in Go style. So now you can do something like:

fun squareManyNumber(List<Int> numberList): List<Int> {
    val squareChannel = Channel<Int>()
    launch {
        numberList.forEach {
            channel.send(square(it))
        }
    }
    val resultList = mutablieListOf<Int>()
    repeat(numberList.size()) { resultList.add(squareChannel.receive()) }
    return resultList
}

It

This is the default name for parameters into blocks. The first time you see it it is kind of weird. But then you get used to it and it is convenient in some code. And for multi line blocks it is often wise to use a parameter name instead. But as always it depends. You can see it being used above.

Nested functions

It is possible to declare functions inside a function local to that scope. This can be really convenient when you have lots of parameters and don’t want another parameter list. It is a bit like let in other languages. Silly exmple below:

fun square(x: Int): Int {
    fun internalSquare(): Int = x * x
    
    return internalSquare()
}

Extension functions

Sometimes called monkey patching. It is possible to add functions to any class which makes it much easier to write readable code but can cause confusion at times. We use it both for standard library classes and our own classes. Lets add square to the Int class as an example:

fun Int.square(): Int = this * this

Yep quite intuitive right?

Things I don’t like

Typed functions

Well this is a language with static types so you natrually have to type things all over the place. Type inference works as it should so it is just as much as necessary. But consider a function that returns another function. Sometimes I like to generate small functions. Here the type of that function is so hard to parse that it is almost never worth the effort. Too much noise and better solved in some other way.

Linter

Well I Really like that there is a common idea on what the code should look like. I just don’t like what that is. But better that all code is formatted in the same way then it can vary inside a code base. For me the linter is much too aggressive with line breaks. Whenever you have a multi line function call it will need a line break for each part of the signature. I don’t mind named parameters and multi line calls at times but sometimes I just want something compact instead. It depends on the context.

Summing it up

There are quite a few more things I don’t like but overall there is much to like with the language. It is a much nicer developer experience as compared with Java. Personally I prefer dynamic like languages like Python or Ruby. They help me write the most readable code that can also be beautiful. With types there is some more noise that gets in the way. For code bases that will likely see many developers over the years I believe that there is no point avoiding static typing. The few bigger dynamically typed systems I have seen has been really hard to maintain. It takes some testing to keep them stable and maintainable. And testing is not something every developer will do. Most develoeprs that do test does it after the fact so it is likely that parts of the code does not have that code test coverage. Kotlin comes as far as is possible to be light weight while still have the rigouorsness of static types.

written by fredrik at 2024-11-06

More content on code

More content on kotlin

More content on programming