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.
And Thats it!! Feeling little confident? Answer this question in comments :)
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}
}
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