From the Kotlin documentation, custom setters are allowed:
class Test {
var stringRepresentation: String
get() = field
set(value) {
setDataFromString(value)
}
init {
stringRepresentation = "test"
}
private fun setDataFromString(value: String) { }
}
But you cannot have a custom setter without a custom getter (and initialize from the init
block):
class Test {
// Compilation error: "Property must be initialized"
var stringRepresentation: String
set(value) {
setDataFromString(value)
}
init {
stringRepresentation = "test"
}
private fun setDataFromString(value: String) { }
}
Although you can have a custom getter without a custom setter, no problem here:
class Test {
var stringRepresentation: String
get() = field
init {
stringRepresentation = "test"
}
private fun setDataFromString(value: String) { }
}
So why can't you use a custom setter with a property initialized from within the init
block, and why does the init
block invoke the custom setter while the property initializer assigns directly, bypassing the custom setter?
class Test {
var stringRepresentation: String = "" // Does not call custom setter
set(value) {
setDataFromString(value)
}
init {
stringRepresentation = "test" // Calls custom setter
}
private fun setDataFromString(value: String) { }
}
Property initializers doesn't call custom setter because their purpose is to provide the default value.
Unlike in Java, in Kotlin not only local variables must be initialized before their first access but class properties as well.
In Java this is valid.
public class Test {
public String str;
public static void main(String[] args) {
System.out.println(new Test().str);
}
}
In Kotlin this is not.
class Parent {
var str: String?
}
fun main(args: Array<String>) {
Parent().str
}
For this reason custom setter needs its property to be initialized either by property initializer or by the constructor. Take a look at the following example.
class Test {
var stringRepresentation: String = "a" // Default value. Does not call custom setter
get() = field
set(value) {
println("Setting stringRepresentation property to %s. Current value is %s.".format(value, field))
field = setDataFromString(value)
}
init {
this.stringRepresentation = "b" // Calls custom setter
}
private fun setDataFromString(value: String): String {
println("Setting stringRepresentation property to %s.".format(value))
return value
}
}
fun main(args: Array<String>) {
Test().stringRepresentation = "c" // Calls custom setter
}
Property stringRepresentation is initialized to "a" opon instantiation of its class without calling setter. Then init block is called and sets value to "b" using setter. Then to "c" using setter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With