https://kotlinlang.org logo
#getting-started
Title
# getting-started
d

dirk.dittert

01/26/2022, 3:27 PM
I have a question about constructors in Kotlin. Let's assume the following code:
Copy code
interface Base {
	val number: Int
}

class SomeClass: Base {
	override var number: Int
		private set
		
	init {
		number = 42
	}

}
This results in an error: Property
number
must be initialized. I did not expect this as the documentation says that the code in the init block effectively becomes part of the primary constructor. There seems to be a workaround by changing the
init
block to:
Copy code
constructor() {
    number = 42
}
But that's something inspections don't like so much (secondary constructor should be converted to primary constructor). Is this intended behaviour?
m

Matteo Mirk

01/26/2022, 3:51 PM
Why is it val in the interface but var in the concrete class? Also, why do you need it to be mutable only privately, is it intentional?
d

dirk.dittert

01/26/2022, 4:20 PM
This is a distilled down example. Clients code against the interface
Base
and that provides only read only access. Internally, there can be setters for properties as well (as in my example here)
m

Matteo Mirk

01/26/2022, 4:23 PM
I see thanks
d

dirk.dittert

01/26/2022, 4:24 PM
And: Kotlin is fine with the code if the implementation class also declares the property as
val
(in combination with an
init
block).
m

Matteo Mirk

01/26/2022, 4:27 PM
yeah I tried that locally, so that’s why I asked if it was necessary to have it var but with private setter 🙂
d

dirk.dittert

01/26/2022, 4:38 PM
Yes, it is necessary.
e

ephemient

01/27/2022, 3:47 AM
Copy code
override var number: Int = 42
    private set
is it not possible to initialize normally?
💡 1
d

dirk.dittert

01/31/2022, 9:08 AM
The value was generated dynamically in the constructor of the class. In this case by reading environment variables.
e

ephemient

01/31/2022, 9:16 AM
in that case you still have an ugly workaround,
Copy code
override var number: Int = 0
    private set
init {
    number = 42
}
oh, another option is
Copy code
final override var number: Int
    private set
init {
    number = 42
}
essentially, Kotlin does not want the uninitialized backing field to ever be observable, but if the property is open, then that can't be guaranteed
so it either must be initialized in a way that doesn't go through an overridable setter (e.g.
override var number: Int = 42
initializes the field directly), or the setter must not be overridable (as a subclass could then observe the uninitialized state)
although I do see an argument that this being confusing given that the class itself is not open, but that's a different issue…
d

dirk.dittert

01/31/2022, 10:38 AM
I think, my issue with this is, that Kotlin seems to be fine if the property is initialized in a secondary constructor but not in an
init
block.
e

ephemient

01/31/2022, 10:51 AM
init blocks are run along with property initialization in declared order, whereas a constructor is run last, after super constructor has been called
👍 1
☝️ 1
4 Views