The argument of declaring constants

header by @alevisionco from Unsplash


In Kotlin we have 3 main different options to declare a constant. One of those options is keeping the constants shared in one object, this is simple enough and doesn’t have any bad consequences for usability, maintainability or performance but this is only suitable for global constants, So in order to create some locally scoped constants, we have to go with the other 2 options. those 2 options created some confusion for us as developers on When to use option X over option Y, so I’m gonna talk about those 2 options and a third option which is creating constants with just a val without const modifier from usability and performance perspectives.

1. First Option: Declare Constants as a top-level values in the same file

But anyway this is gonna be converted to Java bytecode when compiled, So how Kotlin tell Java about top-level constants because Java doesn’t have such a concept, If we look at the decompiled bytecode, we will see:

Kotlin will create a class with the name of our file for us and all of the constants will be marked as static , So when invoking a constant from those no object allocation will happen or unnessacary object creation, Thus we see that this option has no overhead at runtime, but wait before you judge we still don’t know about other options, Also some people(including me in some situations) will not prefer this option because declaring constant as a top-level sometimes doesn’t provide a strong indication (compared to other options) that it is related to class/functions defined in the same source file.

2. Second Option: Declare constants in a companion object

if We look at the decompiled bytecode this time:

Similar to what we saw before but this time with a new class called Companion created for us and also a new instance of it created automatically, in comparison with the previous approach we can see the previous one outperforms this approach from a performance perspective because of the new unnecessary object allocated But on the other hand this approach represent the constants in a more structured and semantic way compared to the previous one.

NOTE: Using R8 with optimization enabled can eliminate/remove this unnecessary object allocation and move the field/method to outer class (i.e Wrapper ) plus making it a static instead of member/virtual property. This Process is called Staticization.

If you haven’t heard of this term before? check R8 Optimization: Staticization by Jake Wharton

We can now easily choose what is more convenient For us, So are we done yet? No, there is third option we haven’t covered yet.

3. Third Option: Declaring constant with just val without const

If we look at the decompiled bytecode:

As you can see, nothing fancy is happening here. it is merely identical to the decompiled bytecode of 2 previous approaches. But let’s make a small change: we will change the access modifier of the field from private to public

will it differ from the previous? Let’s see:

And the decompiled bytecode:

similar to the previous, but this time with a public getFoo() generated for us and changing our public field to private one, So we can access the field through its getter method, and that may annoy some of you who still think accessing getter method is more expensive than accessing the field directly.

Fortunately, Android Runtime is smart enough to inline trivial getter method like the one we have above, So you don’t get any performance hit. see this article for details.

Moreover, not just the ART that is smart, R8/Proguard also could inline(Assuming optimization is enabled) that method for you as well. So if you don’t believe yet in ART optimization, you will have R8 do it for you.

So, what to do now?

Basically, I have shown you the different options and shared my humble opinion with you. Personally, I prefer approach #2. But in the end, choose whichever convenient for your situation/use case.

Still not Convinced/Hungry? I got more References for you:

2- This StackOverflow post

3- A series by Jake Wharton on R8, D8 Optimizations

Eager to learn more and more! I hate boilerplate. I blog to share some tips & tricks and to talk about my humble opinion.