Reputation: 2220
I was creating a very simple kotlin program and saw a weird behavior for parent class.
The code is:
fun makeSalt(name:String) = Spice(name, "non-spicy")
fun main(args: Array<String>) {
var salt : Spice = Spice("salt", "non-spicy")
println("Salt heat = ${salt.heat}")
val spicelist = listOf<Spice>(
Spice("salt", "non-spicy"),
Spice("turmeric", "mild"),
Spice("Pepper", "hot"),
Spice("Chilli", "hot"),
Spice("Sugar", "non-spicy")
)
val mildSpices = spicelist.filter{it.heat <=5}
val salt2 = makeSalt("rock salt")
val bhoot : SubSpice = SubSpice("bhoot", "hot")
}
open class Spice(open var name:String, open var spiciness:String = "mild" ){
var heat : Int = 5
get() = when (spiciness){
"mild"->5
"hot"->10
"non-spicy"->1
else -> 0
}
init{
if(spiciness === null) {println("spiciness is null")}
else println("Spiciness of ${name} = ${spiciness}; heat = ${heat}")
}
}
class SubSpice(override var name:String, override var spiciness:String = "hot") : Spice(name, spiciness){
}
When I execute this program, the output is:
Spiciness of salt = non-spicy; heat = 1
Salt heat = 1
Spiciness of salt = non-spicy; heat = 1
Spiciness of turmeric = mild; heat = 5
Spiciness of Pepper = hot; heat = 10
Spiciness of Chilli = hot; heat = 10
Spiciness of Sugar = non-spicy; heat = 1
Spiciness of rock salt = non-spicy; heat = 1
spiciness is null
As you can see, when I created an object of the sub-class, the variable spiciness
of parent class becomes null. Can someone explain why is that? I expected it to be null since it also has default parameter of "mild"
Upvotes: 1
Views: 656
Reputation: 1384
To add extra information to Pawel's answer:
If you are overridding properties using open
, the init block in the base class will run before the derived properties have been initialized.
See docs: https://kotlinlang.org/docs/reference/classes.html#derived-class-initialization-order
So if we change the code like Pawel suggested, we end up with something like this:
fun main(args: Array<String>) {
Spice("salt", "non-spicy")
Spice(name="spice")
SubSpice(name = "bhoot", spiciness = "hot")
SubSpice(name="subspice")
}
open class Spice(var name:String, var spiciness : String = "mild" ) {
var heat : Int = 5
get() = when (spiciness){
"mild"->5
"hot"->10
"non-spicy"->1
else -> 0
}
init{
if(spiciness === null) {println("spiciness is null")}
else println("Spiciness of ${name} = ${spiciness}; heat = ${heat}")
}
}
class SubSpice(name: String, spiciness : String = "hot") : Spice(name, spiciness) {
}
Which outputs:
Spiciness of salt = non-spicy; heat = 1
Spiciness of spice = mild; heat = 5
Spiciness of bhoot = hot; heat = 10
Spiciness of subspice = hot; heat = 10
Upvotes: 2
Reputation: 17258
You are you using open var
when you're not overriding any getter/setter methods.
You're introducing weird initialization conflict since Spice.init
(parent class constructor) is invoked before SubSpice.init
and by overriding the fields they are no longer initialized alongside parent constructor - instead they will be available once Subspice
is constructed.
Remove open
keyword from variables in parent class and override var
in child constructor, that way fields will be properly initialized in Spice
class and its init
block should run successfully.
Upvotes: 5