Initialization of delegated properties

Hello,

I’m using delegated properties like

class Example {
val defaultInstance: ItemClass
get() {
return items.firstOrNull() ?: ItemClass().also { items.add(it) }
}

override var propA: String by defaultInstance::propB
}

In short words: I’m going to delegate some properties to the first item in a list of items.If no item exists I create an initial item.
The given code is not working, since the property propA is “initialized” in the constructor. I’m wodering, since the propA does not have any internal field and no state. The delegated property defaultInstance does not have an internal field as well. The code fails in my deserialization method, which reads all states from the a Json stream. Since the unnecessary initialization an initial item (ghost item) is created.

Why Kotlin initializes a delegated property without an internal field? Is there any other approach, which fits better to my use case?

Thanks for your help!

Matthias

A change to
override var propA: String
get()= defaultInstance.propB
set(value) {defaultInstance.propB=value}

works fine. But I don’t understand, why the property delegate triggers a get during the object initialization. In the alternative approach get/set such an initialization is not done and not necessary.

I don’t have an answer, but you may be able to shed some light by printing a stack trace in the getter, to show what’s calling it.

When we do by expressionToAcquireDelegate then the code on the right side is executed only once at the initialization time. Otherwise, code like by lazy { 5 } would create a new lazy object every time we use a property which is not what we expect.

In your case that means you acquire defaultInstance during initialization, not when accessing propA.

The getter is called directly by the constructor (before init method). I think, the property is handled like a var or a “by vetoable(init value)” property, which needs such kind of initialization step. But in my case this is a critical behavior since the delegation is not yet working before the initialization is finished. This will disturb all de-serialization calls.

I used the approach as a workaround for the lack of missing interface delegation for var properties. Now I’m falling back to my own implementation of the properties with getters/ setters.

Matthias

That’s, what I can see in the behavior.
But I think, there are some important differences between “by lazy {5}” and “by myProperty::delgateProperty”. The “by lazy” construct assigns a value to the internal field of the val property (initialization). This is like “by vetoable” or “by observable” - all those kinds of delegation approaches have an internal state.
But the property delegation, which forwards getters and setters does not need any internal field and therefore no initialization. It might be also critical in sense of the dependency between the property and its delegation property with respect to their order of initialization.
Another argument is, that most likely any call to the getter of such a property is forwarded to the delegation.

best regards,

Matthias

That would require adding some strange exception to how property delegates work. In all cases they are initialized at the object initialization time and the delegate itself is stored as a member. Your suggestion means the compiler would have to scan the code for this specific type of property delegation and treat it differently than all other property delegates. I don’t have to mention such exceptional behaviors are a bad idea in the language design. And what if we have a function loadSomethingHeavy() that returns KProperty and we use it in by? Should it be invoked during initialization or whenever we access the property?

1 Like