Could you explain me why the line it.protectedProperty = 0
in the CompositeImpl
class doesn’t work?
// Kotlin 1.4.21
sealed class Component {
var protectedProperty: Int = 0
protected set
abstract class Leaf : Component()
abstract class Composite : Component() {
abstract val children: List<Component>
}
}
class CompositeImpl : Component.Composite() {
private val _children = arrayListOf<Component>()
override val children: List<Component> by ::_children
fun a() {
// This works.
protectedProperty = 0
}
fun b() {
children.forEach {
// This does not work.
// error message: Cannot assign to 'protectedProperty': the setter is protected in 'Component'
it.protectedProperty = 0
}
}
}
protected — same as private + visible in subclasses too;
(https://kotlinlang.org/docs/reference/visibility-modifiers.html)
I thought the code would work because CompositeImpl
is a subclass of Component
…
Am I misunderstanding the protected
modifier?
1 Like
it
’s type is Component (which doesn’t have that property), not CompositeImpl. If it
’s type were CompositeImpl (by casting, or some other way) then that work
1 Like
Thanks for your reply!
I added new code to fun b()
// class CompositeImpl
fun b() {
children.forEach {
// This does not work.
// error message: Cannot assign to 'protectedProperty': the setter is protected in 'Component'
it.protectedProperty = 0
}
(it as? Component)?.protectedProperty = 0 // error
(it as? Composite)?.protectedProperty = 0 // error
(it as? CompositeImpl)?.protectedProperty = 0 // OK
}
CompositeImpl
is a subclass of Composite
and Component
.
Why does only the last one (casting to CompositeImpl
) work?
it’s type is Component (which doesn’t have that property)
Could you explain more about the “which doesn’t have that property” part?
I have declared that property in Component
.
2 Likes
It does. It’s exactly Component
where that property is declared. So there must be another reason.
My guess is that it is done to only allow classes to access their own properties. When you access this.protectedProperty
, it’s OK because once you inherited that property, its your own business what you do to it. But when you access it.protectedProperty
, and all you know about it
is that it some subclass of Component
, then it’s no longer your business. If such access was allowed, then in order to understand what happens to a certain property, one would need to locate all subclasses and study their source code.
Example. Suppose Component
is a part of a library A, and CompositeImpl
in in some 3rd party plugin B that uses the library. Now, a user of the library developing module C declares a subclass of Component
and calls it MyComponent
. It inherits that property, and uses it for its own purposes. Then, at some point, that CompositeImpl
randomly changes this property of one of its children which happens to be of MyComponent
class at run time. Now the developer of C is really confused because all they know is that they didn’t change it, and they know neither did A (from its docs or from sources if it’s an open source library). Since they are not even aware of B’s existence, the confusion is next to impossible to clear up.
Therefore, it makes sense that a protected property can only be accessed by a class that owns it (either because it declared it, like with a private property, or because it inherited it, that what makes it different from a private property). Accessing properties of classes that are its siblings and cousins, or potentially could be its siblings or cousins, are not allowed.
2 Likes