Constructors don't print out

Why the following code doesn’t print out the constructors values?

class Vehicle(
    val make: String, val model: String,
    val year: Int, val state: String = "CA"
) {
    override fun toString(): String {
        return "$year $make $model ($state)"
    }

    init {
        println("First initializer block - $this")
    }

    constructor(
        make: String, model: String,
        year: Int, state: String, style: String
    ) : this(make, model, year, state) {
        this.style = style
    }

    constructor(
        make: String, model: String,
        year: Int, state: String, style: String,
        status: String
    ) : this(make, model, year, state, style) {
        this.status = status
    }

    private var style = ""
    private var status = ""


}

fun main() {
    val car = Vehicle("Chevrolet", "Volt", 2018)
    println(car)
    val car2 = Vehicle(state = "NV", year = 2019, make = "Ford", model = "Mustang")
    println(car2)
    val car3 = Vehicle("Tesla", "Model S", 2019, "RI", "P100D")
    println(car3)
    val car4 = Vehicle("Tesla", "Model 3", 2019, "CA",
        "Performance", "New")
    println(car4)
}

I get following output

First initializer block - 2018 Chevrolet Volt (CA)
2018 Chevrolet Volt (CA)
First initializer block - 2019 Ford Mustang (NV)
2019 Ford Mustang (NV)
First initializer block - 2019 Tesla Model S (RI)
2019 Tesla Model S (RI)
First initializer block - 2019 Tesla Model 3 (CA)
2019 Tesla Model 3 (CA)

Isn’t this what you expect? What value do you expect to be printed that is missing?

1 Like

I expect the output including the constructors values.

In that case there are 2 issues with your code. The first is your print statement or to be more precise the toString method.
Whever you have something like println(this), println(someObject), println("someText $someObject"), etc kotlin calls someObject.toString() to figure out how to represent the object as text. Your toString function however does not include all properties of your class. Only those that are in your toString method will also apear in the output.

But changing this is not enough in your case, because the primary constructor will always be called before any code in your secondary constructor. This means that the init-block with the println call will be executed before you set status or style. To change this you would need to rework your code quite a bit. The easiest however is to simply combine all constructors and use default values.

class Vehicle(
    val make: String, 
    val model: String,
    val year: Int, 
    val state: String = "CA",
    private var style: String = "",
    private var status: String = ""
) {
    init {
        println("First initializer block - $this")
    }

    override fun toString(): String {
        return "$year $make $model ($state) - $style $status"
    }
} 

You can also use data classes to generate the toString method for you. This comes with some additional advantages (generated equals and hashCode) and some disadvantages (limited inheritance).

data class Vehicle(
    val make: String, 
    val model: String,
    val year: Int, 
    val state: String = "CA",
    private var style: String = "",
    private var status: String = ""
) {
    init {
        println("First initializer block - $this")
    }
}
2 Likes