Blitzer
10/13/2022, 3:30 AMKevin Healy
10/13/2022, 3:51 AMKevin Healy
10/13/2022, 3:54 AMBlitzer
10/13/2022, 2:14 PMKevin Healy
10/13/2022, 3:39 PMRuckus
10/13/2022, 4:22 PMclass Thing(val name: String, val count: Int) {
// Call primary constructor directly
constructor(name: String): this(name, 1) {
println("Using default count")
}
// Call primary constructor indirectly
// through another secondary constructor
constructor(): this("N/A") {
println("Using default name")
}
// INVALID: Doesn't call primary constructor
constructor(a: Int, b: Int) {
println("Nope")
}
// INVALID: Delegated constructor never calls primary
constructor(a: Int): this(a, 0) {
println("Nope")
}
}
Blitzer
10/14/2022, 3:33 AMclass Playground(val name: String, val count: Int) {
// Call primary constructor directly
constructor(name: String) : this(name, 1) {
println("Using default count")
}
// Call primary constructor indirectly
// through another secondary constructor
constructor() : this("N/A", 2) {
println("Using default name")
}
}
I was playing around with this, and I came across this situation when i tried calling the primary constructor directly from both of my secondary constructors, and the result was "Using default name", why didn't the first constructor run?Alan B
10/14/2022, 1:43 PMval a = Playground() // prints "Using default name"
val b = Playground("Single Parameter Constructor") // prints "Using default count"
val c = Playground("Calls Primary Constructor", 23) // prints nothing as it's the primary
I’m not sure what you mean “why didn’t the first constructor
run”? It runs if you pass a single string parameter.
You can have the “second” constructor
call the “first”, which in turn calls the primary:
class Playground(val name: String, val count: Int) {
// Call primary constructor directly
constructor(name: String) : this(name, 1) {
println("Using default count")
}
// Call primary constructor indirectly
// through another secondary constructor
constructor() : this("N/A") { // calls the "first"
println("Using default name")
}
}
Side note:
I’m not a fan of overloading constructors. I try to look for ways to default the parameter values in the primary whenever possible. This example can be reduced to:
class Playground(val name: String = "N/A", val count: Int = 1)
Ruckus
10/14/2022, 2:50 PMthis("N/A", 2)
which calls the primary constructor (with a signature of Thing(String, Int)
). I wrote this("N/A")
which calls the other secondary constructor (with a signature of Thing(String)
). You definitely don't want all constructors to run every time, that would completely violate the purpose of having multiple constructors.
If you think about your code, what do you expect the value of count
to be if both constructors run, 1
or 2
? It can't assign one then the other as count
is final, so which one wins? And if one wins, why run the other at all?Ruckus
10/14/2022, 2:52 PMAlan B
10/14/2022, 3:06 PMinvoke
on a companion object while keeping the constructors private. I often forget how to write a constructor as I just avoid the spaghetti code of the combinatorics of creating instances via constructor args and having to figure out the best way to provide proper hidden defaults. Complex constructors are a code smell (to me). I also avoid subclasses like the plague. That’s a different topic altogether. 😄