Tuesday, 29 October 2019

Kotlin Class Properties and Backing Field. An Insight

Lets deep dive and understand the Kotlin class properties and backing fields!

Its a deep dive and expect understanding of 'class property', 'backing field' in Kotlin. If you don't know then please first read the official 1 page documentation for the same.

Official link: https://kotlinlang.org/docs/reference/properties.html#backing-fields.
And I am sure you will visit this page again with a bunch of question while trying to wrap your understanding around it. And this is the reason that I wrote this blog to help fill those gaps.  

Question that I am going to answer:

1. We needed to provide Initializer while defining the property. Why? Are there cases where we don't have to provide Initializer to be able to compile code? What happening behind the scenes? 

Answer: Kotlin Initializer assigns the value to the automatically generated backing field for the property. So that means, If there is no backing field [in some cases] then we don't need to provide the initializer too!  So that lands us at question#2

2. When do Kotlin generate Backing field, and when not ?

1. If you use at least one of the default accessor method i.e getter or setter Then Kotlin is going to generate a backing field for that property. Contrary, If you happen to override both of get() and set()[When applicable] methods. Then backing field is not generated.

2. If you happen to use 'field' keyword in the overridden accessor methods. Then Kotlin generates the backing field  and you will have to provide initializer when defining the property. 

e.g. 

class Test{
    

       //No backing field generated. Because all of the accessors were overridden and 'field' is not used in overridden methods. Hence Notice we didn't even need to provide the initializer, cuz it has not purpose anymore and hence its a compilation error.

        var hasField : Boolean
          get() = false
          set(value){}

     // Backing field not generated, because all of the accessors were overridden. Yes All, because read-only property defined using 'val' keyword doesn't have setter. And 'field' is not used. Hence backing field is not generated and so we cannot provide initializer. 

        val hasValField : Boolean
             get() = false 

      // Backing field is generated. And hence we needed to provide initializer to compile the code. 

       val example2: Boolean = true
          get() = field > 100

    // Backing field is generated because setter is not overridden and hence we need to provide Initializer.

     var example3: Boolean = true
        get() = true;

// Backing field is generated, because we used 'field' in the accessor methods. Hence we must provide the initializer.

    var example4: Boolean = true
      get() = true
      set(value){field = value} 

}

3. Why do Backing field exist? 

Answer: Its because of the way Kotlin works! Lets take an example.

class Test{
     var foo = false
        get() = foo
}

You may think this code will work, but you will sendup in 'StackOverFlowException'. Android studio should be able to report this problem,

Whats the problem?
The call get() = foo, while trying to return foo from the getter the Kotlin will implicitly call the get() again, so get() calls get() and keep doing that recursively, and when you go out of runtime stack memory. The program will crash!

So the easiest workaround to fix this code is

class Test{
     var foo = false
        get() = field
}

Because remember from above 'field' is implicitly created backing field and assigned 'false' by the property initializer provided.

another example to work with Setter method

class Test{
     var foo = false
        get() = field
        set(value) {field = value}
}


And Thats it!! Feeling little confident? Answer this question in comments :)

No comments:

Post a Comment