Safely accessing lateinit properties in Kotlin
Rahul Chowdhury 🕶

Rahul Chowdhury 🕶 @rahulchowdhury

About: Android Engineer with over 3.5 years of experience. Writes code in Kotlin, Ruby and JavaScript.

Location:
Bangalore, India
Joined:
Feb 21, 2019

Safely accessing lateinit properties in Kotlin

Publish Date: Apr 9 '19
7 8

Kotlin, by design, doesn't allow a non-null variable to be left uninitialized during its declaration.

If you've been digging into Kotlin you'll know that a lateinit property allows you to overcome this hurdle.

However, if you're a complete newbie, lateinit allows you to declare a variable first and then initialize is some point in the future during your app's execution cycle.

All these seem rosy, so where's the problem?

The problem occurs when you try to access an uninitialized property. Let's talk more about that.

Accessing an uninitialized property

Whenever you declare a lateinit var, you need to initialize it before you access it. Otherwise, you'll be greeted with a fancy exception like this:

Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property fullName has not been initialized
    at UninitializedPropertyKt.main(UninitializedProperty.kt:3)

Don't mistake this for a puny exception. It'll crash your app.

And this is a very common situation to run into. Take this as an example:

You might have a list data being fetched from a remote server and need to initialize a RecyclerView adapter based on that data.

What happens when you try to access that adapter before you actually get the data from the remote server?

Boom! Your app crashes.

So, how to solve this problem?

Taking the rookie approach

The most lucrative solution to this problem would be to make the property a regular nullable one instead of a lateinit var and assign a value later on.

You can do something like this:

var fullName: String? = null

And then just do a plain null check whenever you're accessing the value.

if (fullName != null) {
    print("Hi, $fullName")
}

Kind of like Java. But hang on a sec, Kotlin is supposed to be better than Java. Also, one of the USPs of Kotlin was eliminating the fiasco caused by a NullPointerException.

So, why go the traditional route?

Here's a better solution.

Going the Kotlinish way

If you're using Kotlin 1.2, you can easily check whether a lateinit variable has been initialized or not. If not, well, you can always use the not null approach.

Anyways, here's how you can check if a lateinit var has been initialized or not:

if (::fullName.isInitialized) {
    print("Hi, $fullName")
}

According to the official blog post announcing this update, this approach uses reflection to check whether the value has been initialized or not.

Also, a deinitialize method is due for rollout in a future release, probably in Kotlin 1.3.

What's the motivation here?

When I first encountered the exception mentioned in this article, I had two choices:

  • Go the traditional not null way
  • Do some cool shit

I took the latter approach.

I didn't want to litter my code with null checks. Also, this looks more meaningful.

Traditional is, well, traditional. Go along with the new.

This article was originally published at upcurve.engineering.

Comments 8 total

  • Trevor Nemanic
    Trevor NemanicApr 10, 2019

    This is pretty cool, indeed. Wouldn't the reflection be a more costly solution(in terms of performance) than a simple null check?

    • Rahul Chowdhury 🕶
      Rahul Chowdhury 🕶Apr 10, 2019

      Haven't noticed any performance issues regarding this, Trevor. Open to some deeper insights, though.

      • Trevor Nemanic
        Trevor NemanicApr 10, 2019

        Reflection has a performance penalty in Java

        stackoverflow.com/questions/435553...
        From SO: Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.

        IMHO, it wouldn't hurt to use lateinit properties judiciously, but relying on them would hurt your performance (eg. looping over a Collection).

        • Rahul Chowdhury 🕶
          Rahul Chowdhury 🕶Apr 10, 2019

          Yes, I agree that reflection is slow and overuse of reflection can slow down your application. However, as you said, wise usage of this syntactic sugar won't do much harm.

  • Giorgos Neokleous
    Giorgos NeokleousApr 25, 2019

    So, you are using lateinit, which offers immutable objects, but you still have to surround it with conditional checks (which checks are being done using reflection).

    How is this better and "not the rookie" way?

    In my opinion it depends on the situation. If you find yourself having to make lateinit properties either nullable or having to wrap them with #isInitialized then you need to rethink your architecture. It always depends on the problem you are trying to solve ofc.

    Reflection is expensive and it shouldn't be the rule of thumb to use over nullable properties.

    • Rahul Chowdhury 🕶
      Rahul Chowdhury 🕶Apr 26, 2019

      Hey Giorgos, this might not be the best way to approach the "empty state" issue but it's certainly a neat trick that you can apply using the Kotlin standard library.

      How you approach the problem and architect your application differs from person to person, isn't it?

      This is just one way of doing it. :-)

      • Giorgos Neokleous
        Giorgos NeokleousApr 26, 2019

        Of course it depends on the person and the team. I think you shouldn't put the label

        Taking the rookie approach

        For wrapping properties with is not null conditions. On runtime the null check is theoretically faster than the approach described above.

        Another way of solving it, it's to design the application in such way that race condition doesn't happen. Try and access the property when and only when is initialised and not before that. So that you avoid such issues.

  • Danilo Oliveira
    Danilo OliveiraFeb 11, 2020

    Can I have a Future that is completed when the property is initialized? This would be much more convenient than the .isInitialized method.

Add comment