loading...
Cover image for A decompiled story of Kotlin let and run

A decompiled story of Kotlin let and run

vlazdra profile image Vladimir Zdravkovic ・4 min read

Introduction

A while ago I spent quite some time trying to figure out why a simple block of Kotlin code didn't want to do what I was wanting it to do. After numerous attempts on rewriting my code, thinking that it must've been a mistake on my end, I decided to dive into the generated code to try and figure out what happens in the background.

The topic is let and run, the 2 inline functions from the standard Kotlin library available to developers. The way I thought that let and run work in combination was in a similar way to a classical if/else statement. So I started and continued using them like that, until a ran into a wall when I was implementing something in one project.

Let's take a look at what the issue is:

Example 1 - Kotlin

So in this example we have a simple Kotlin class with 2 nullable variables of which one is already defined with a value. Now, looking at the code the question is, what would be printed in the console if I would to call doSomeAwesomePrinting()?


If you said nothing, sorry to say, that would be incorrect. The correct answer would be "awesome output 1".
I know, it doesn't make any sense, right?

What's going on here? Let's decompile this simple example into Java and see what happened:

Example 1 - Java

Ok ok, now this makes sense, I mean the code. We can clearly see that this function will execute to the end and print the "awesome output 1" at the end because the second variable was indeed null and it wouldn't do the return.


Now let's take a quick look at one more example and find a solution together in the end.

In this next example we will only change one thing, and that is to add the run block, or the elvis operator on the second variable let operation:

Example 2 - Kotlin

What do you think would be printed if the doSomeAwesomePrinting() function was called again?
Yes, it will print out "awesome output 3"!

Now this one does what you'd want it to, it feels like a real if/else statement. And the Java decompiled code does confirm that as well:

Example 2 - Java


Solution! (kinda)

Thanks to Danny for mentioning it, it would seem that a different Kotlin inline function would do the trick.

So after trying out what Danny suggested, it worked! Now let's take a look at what happens under the hood when using the apply Kotlin inline function on the same examples from before.

Example 3 - Kotlin

Output? Nothing actually. Let's see what the decompiled code looks like with this example and try to understand the mechanics:

Example 3 - Java

After decompiling the same block but with apply we now have a different Java code, that does not output anything as one would expect.

And finally let's look at one more example where we would catch the null value of the inner variable with the elvis operator and the run block:

Example 4 - Kotlin

Anyone interested in the output? The console will have "awesome output 3" printed out since the awesomeVar2 is null. Let's dive into the Java decompiled code to get a better understand what happened here:

Example 4 - Java

A bit more complex than the previous examples but approximately the same result, the console will output "awesome output 3" as it was intended to, and we know have a better picture as to why and how.

Part 2 ?

In part 2 of this topic, we will dive deeper on how the Kotlin compiler compiles the inline functions from the standard library and to better understand the behaviour mentioned in this article. So stay tuned.

In the meantime you can always dive into the source code of theses specific functions, let, run and apply.

Conclusion

While you can of course still use the let inline function normally as you already have, just be careful of the effect mentioned in this article and make sure that your use case works as expected.

It is always fun to discover things like this, to get a better understanding of the tools and languages we are using on a daily basis. By discovering things like this we improve ourselves, but by also sharing it we help others improve themselves as well.


With that, I would like to thank you for reading through to the end of this article. I really hope it gave you some clarity over how the Kotlin code gets generated to Java, and how this specific topic could affect the code you write everyday. If you found this article interesting, please feel free to share it, and give a like bellow.

Note: The decompiled Java code shown in this post is not the exact equivalent to the one that gets generated. I removed the unnecessary code in order to make it shorter and a little bit more readable for the purpose of this article.

Posted on by:

vlazdra profile

Vladimir Zdravkovic

@vlazdra

I see myself as a passionate developer interested in a multitude of languages and topics! Currently my focus is on Android\Kotlin full time with Flutter\Dart lurking from the shadows. #extrovert

Discussion

markdown guide