15

I have a lateinit var as

lateinit var someVariable: SomeVariable

I initialize this value like someVariable = SomeVariable() and use it whenever I need.

At a certain point, I want to set everything to default and want to "uninitialize" someVariable. How can I do that?

I am not looking for changing its type to a nullable object and set null. I need to keep it a Non-Null type.

Ashraf Patel
  • 699
  • 1
  • 7
  • 17
musooff
  • 6,412
  • 3
  • 36
  • 65
  • 1
    I am just trying to understand your use-case. Why do you want that property to be uninitialized again? – Ashraf Patel Oct 11 '19 at 06:27
  • You could use a workaround and use a delegate reset for the field, like suggested here: https://stackoverflow.com/questions/35752575/kotlin-lazy-properties-and-values-reset-a-resettable-lazy-delegate – Neo Oct 11 '19 at 06:32
  • @AshrafPatel The use-case is straingt-forward: I don't want to handle null-check. I use this variable several times and I just don't want to check nullability or set it `someVariable!!` even if I know that it is not null. Having non-null variable is what I need. – musooff Oct 11 '19 at 06:38
  • @Neo thanks for suggestion but that looks really complicated for a really simple task. – musooff Oct 11 '19 at 06:39
  • 10
    `lateinit var` is only for first time initialization, for cases when you know that your variable is not nullable but you cannot initialize it in constructor(for example in android framework). There is no point in having `lateinit var` if you "uninitialize" it after. Kotlin does not allow this kind of manipulation. – Murat Mustafin Oct 11 '19 at 06:54
  • 2
    @musooff, so you want to roll back to java way of handling nullables? – user28434'mstep Oct 11 '19 at 08:39
  • What do you want to happen if you access the variable, when it is uninitilaized? – matt freake Oct 11 '19 at 09:34
  • 1
    @mattfreake well for the starter it should give you UninitilizedException as normal. – musooff Aug 21 '20 at 01:37
  • @user28434 thats a good point. But I am just looking for possibilities if there is any – musooff Aug 21 '20 at 01:38
  • Your usecase will probably be better with nullable, because any way you should be checking for isInitialized. However I got a similar problem working with static variables in UnitTesting. I want my unit tests to be clean, so on every run I should clear the static lateinit var. – htafoya Oct 27 '21 at 22:34

1 Answers1

12

I don't think it's possible without some kind of wrapper (or reflection, but about it in a moment).

In fact, lateinit is design for compatibility with DI frameworks etc. If you know the value can be uninitialized in any moment then you should use nullable type.

So, what about that reflection thing? lateinit is in fact a kind of smart wrapper that makes nullable value to act like not nullable, and instead of throwing NullPointerException throws UninitializedPropertyAccessException. lateinit property at the moment of declaration in JVM is null, so, let's make it null again ;)

So...

class MyClass {
    lateinit var lateinitObject: Any

    fun test() {
        println("Is initialized: ${::lateinitObject.isInitialized}") // false
        lateinitObject = Unit
        println("Is initialized: ${::lateinitObject.isInitialized}") // true

        resetField(this, "lateinitObject")
        println("Is initialized: ${::lateinitObject.isInitialized}") // false

        lateinitObject // this will throw UninitializedPropertyAccessException
    }
}

fun resetField(target: Any, fieldName: String) {
    val field = target.javaClass.getDeclaredField(fieldName)

    with (field) {
        isAccessible = true
        set(target, null)
    }
}

fun main() {
    MyClass().test()
}

So, setting that field to null (and it's possible only via reflection) makes this filed uninitialized again. And one important thing - treat it as a curiosity, not like thing that should be in your production code.

Cililing
  • 4,303
  • 1
  • 17
  • 35
  • Nice. Why can't be used in production code? – Pratik Saluja Dec 23 '20 at 07:47
  • 2
    lateinit has a reason to be initialized only once. If there is a need to "uninitialize" a variable nullable type seems to be a good option. There is no value to do it like here, except educational. – Cililing Dec 24 '20 at 11:42
  • This is an awesome solution for testing lateinit variables. It allows the developer to write test code to guarantee that a variable is uninitialized before a test is executed that relies on the variable being so. – pajato0 Oct 04 '21 at 06:29