A decompiled story of Kotlin let and run
Tags: kotlin, java, android
Published: 2020-07-27 13:44:37

#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](https://dev-to-uploads.s3.amazonaws.com/i/e2cq25cuw88xbmrwn73t.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/q7jk4x49aevkpl6tvi57.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/73vutor3kv53wxjpvptw.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/wiegi0gae44mrcxfeidi.png)

---

#Solution! (kinda)

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

{% twitter 1287405807819264001 %}

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](https://dev-to-uploads.s3.amazonaws.com/i/52llc8gatbxg5m01q04m.png)

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

![Example 3 - Java](https://dev-to-uploads.s3.amazonaws.com/i/p4hd1mj0xvk4dv80pvwz.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/2fh2js8jpm1mcurahfsi.png)

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](https://dev-to-uploads.s3.amazonaws.com/i/b9qafyfx7kigvrmnd0o9.png)

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](https://github.com/JetBrains/kotlin/blob/4c91ba90bb2f6437d0e844cfd3b0860f4d0f251c/libraries/stdlib/src/kotlin/util/Standard.kt#L53), [run](https://github.com/JetBrains/kotlin/blob/4c91ba90bb2f6437d0e844cfd3b0860f4d0f251c/libraries/stdlib/src/kotlin/util/Standard.kt#L53) and [apply](https://github.com/JetBrains/kotlin/blob/4c91ba90bb2f6437d0e844cfd3b0860f4d0f251c/libraries/stdlib/src/kotlin/util/Standard.kt#L79).

#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.*