Why Kotlin Sucks

Shk Schneider
ProAndroidDev
Published in
6 min readApr 27, 2019

This article is based on Your Language Sucks. In fact, Kotlin is awesome ❤️, but let’s not be blind to some stuff 👀.

Kotlin: Yay or Nay?

Extensions & Top-Level Functions

Starting with a controversial point here. I’m not against extension functions, at all. But I have a personal warning I wanted high on this list:

With great power comes great responsibilities.

Extensions are a very powerful way to extend a class (firstly that you haven’t written), even to organize. It’s sexy because it lets you do that TextView.boldify() method you found on StackOverflow that you always wanted, precisely as if it was part of the standard framework. It also trims most Utils classes from Java 😌. Oh, and your IDE proposes your extension in autocompletion; you don’t need to know the Util class is there.

And top-level functions… well I’m less kind about those. I feel like methods coming from nowhere as if I was writing inCare a bad thing for the code I write — at least in object-oriented Kotlin.

It lacks of context and namespace (just like static imports, which I also avoid like rats).

Also, they are static

Extensions over top-level functions, definitely. And don’t go too crazy about them. I would simply avoid anything top-level (with a minor exception, more on it below).

Companion Object

Objects are great singletons. Companion objects are also great. But it also feel so wrong (and a lot of weird boilerplate) when I clearly just want a public static somewhere.

It just feel wrong to have that inner companion object inside my class (compared to Java’s static). Actually the Java keyword was not bad. Yes, it’s mostly synthetic sugar but hey..

Besides, who knows if the companion object is at the top or the bottom of the class? 😝 The guideline seems to be “public at the top”, “private at the bottom”, then if you have both, what do you do? 😬 Seriously.

Nowadays, I tend to use top-level private const val/fun for private static things, but I cannot always avoid the inner companion object (that I usually prefer at the end by the way) for visibility reasons.

Name Shadowing & Implicit Property Accessors

This is great. It is great. Name shadowing can really turn into a nightmare at times, and those are only warnings from the compiler.

And all of this is getting worst the more nested your code become. Which it should not be, because we all split code all the time, right? 😏

Even then: have you ever named a variable action? What about in an Activity 🤔 Yeah… you believe you’re referencing your variable while you could be calling the implicit Activity.getAction() instead! 😨

The same happens if you abuse of with or blocks like let because then you don’t know what it is. Because of that, I try to split the code more and tend to set variable name to it: supportActionBar.let { actionBar ->

You can also have colliding names between top-level functions and other methods, and that’s no joke to play around with.

Implicit Returns And Stuff

Would you really had spotted the problem in dense real code? Allways?

If you omit the return (L3) before the when, nothing tells us the code won’t behave as intended (and always return null because the strings are actually unused statements in alwaysReturnsNull()). I much prefer explicit returns and explicit things all the way.

I believe Kotlin is Java with a clever compiler. And that my main goal with this tool is to have safer code while trying to be more powerful and concise. It is not about accepting all IDE’s suggestions and making a minified version of your Java code, which hurts readability. Getting less code is exciting and tempting but it’s not the main purpose of Kotlin, I don’t think.

Maybe a simpler example:

Want something just a bit harder to read?

Using Rx. L2 is an implicit return@map (because of map) while L4 is an implicit return@with (because of with). Sure you got that at a glance 😏, right? I prefer to write those implicit returns in my code rather than relying on my IDE (which, by the way, only helps on the later one). Qualifiers on returns are here to be explicit: return@map

It also feels so wrong to read this:

"" is completely implicit and hard to catch at a glance: it’s actually the return value if !value. It is just harder to read just to gain a few characters. Be careful not to over-minify your Kotlin code.

I also would like to link to another recent article: Advocating against (some) Kotlin expressions.

Also, you can change the signature of a method simply by changing its body in Kotlin..

fun whatDoIreturn1() = "" // implicit String return type
fun whatDoIreturn2() = 42 // implicit Int return type

In this example it’s fine and obvious. Let’s take another example:

L5 is where I got a problem with this syntax and Kotlin’s implicit types.

Now imagine this code being in multiple class and then methodReturningBoolean() changes its return type; or maybe you were reading its boolean value but not anymore. Then beware of where you’re using returnsAnImplicitBoolean().

All that because of that =, not only making the method one-line but also assigning a return type other than Unit. I tend to specify the intended return type for all public methods.

Lambdas as parameters

Lambdas are great. But in Kotlin the use depends on the signature of the code, so a classic fun listener(r: View.OnClickListener) would require to write listener(View.OnClickListener { ... }) and that’s boring.

fun listener(r: () -> Unit) works as listener { … } like I want it to, but that needs another signature of the method.

Potentially requiring to write the same method with two entry points. That’s a bummer, man.

Final classes by default

This is a strange language design, at least to me. Shouldn’t you almost always be able to improve an object, yet be free to lock one in? Maybe I would have preferred a closed keyword, like Java’s final.

Often I end up forgetting that default rules (as are a some library writers), which is simply counter-intuitive to me — and to some library writers too). It seems I’m not the only one.

But hey, since that’s a good practice from Effective Java I’m probably just not used to it 😄

Also: internal is module-restrictive in Kotlin, not scoped to a package.

Compilation Time

Kotlin seems to always take more time to compile than Java. Which makes sense, since I consider Kotlin greatest strength to be it’s smart compiler (not letting you compile instead of printing a warning, for example).

During execution, performances seems on-par and the inline keywords is even bringing optimizations.

So I guess that trade-off is fine. But I couldn’t make a critical article without thinking about that extra compilation time.

Reversability

Java to Kotlin? Not a problem! 😋
Kotlin to Java? Not so much… 😫

Just that. (Although interoperability is superb.)

Final words

This article wasn’t as easy as I would have thought. Mostly because I had to step back and judge the language I do for work. This article was never intended to be fair and is highly opinion-based but I think it’s important to know to criticise something you really got into.

I would sum up that most of the things I don’t quite enjoy in Kotlin are things that are implicit. I like typed and explicit code because I tend to think machines are stupid but effective, and almost all errors are from a programmer somewhere. (Sorry for saying that.) I dislike side-effects and things appearing like magic. Implicit things saved some characters but in the end, I force myself to be explicit. I mean I’m trying. 😉

I’m sure a lot of you would have other points to submit as this is highly debatable. Now is the time to speak in the comments! And be respectful. Thank you 👏

Kotlin, I’m sorry. Don’t be mad. Please don’t go.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Responses (13)

What are your thoughts?