Lazy property observers

I am working on SR-7083 (PR here) which adds support for observers (willSet/didSet) on lazy properties. @jrose mentioned this might need ruling from the Core Team to see whether they think this needs a full proposal or not.

Can a Core Team member confirm whether this needs a proposal or not? cc @Joe_Groff @John_McCall

3 Likes

To me, this seems like a natural composition of existing features. I suppose we could argue whether the didSet/willSet happen "inside" or "outside" the lazy transformation, though property wrappers establish the precedent that observers happen outside the wrapper operation, and that seems like a reasonable model to follow.

5 Likes

At first I thought that this would be a really nice thing to have, but the more I think about the more I am troubled by the semantics of such observers I am...

I would assume the observers are not called for the first get and/or first set, because we don't have an old value we could pass to those observers. That might be unexpected, especially on first write if the property has not been read beforehand.

Could you please confirm what the semantics would be?

Yeah, that’s what I am going for - do not call the observers if the storage does not already have a value (also to be consistent with normal properties (whose oldValue/newValue is non-optional).

It would be more consistent with how property wrappers work with observers to have it always fire after the lazy set operation. A get would not trigger didSet, but as part of the observed set, the initial value will be forced and available as the oldValue.

1 Like

Just to clarify, do you mean we should pass the initial value as both oldValue and newValue or do you mean we should only fire willSet and not didSet?

(this is when we access the lazy property for the first time).

willSet and didSet should both work as they do with other properties, where the oldValue is the result of get-ing the property before the mutation happens, and the newValue is the updated value. For a lazy property, this would mean that oldValue would be the initial value if the property hadn't been forced yet.

1 Like

@Joe_Groff Should this change how non-observed lazy properties work, too? I.e. if a lazy property has a side-effectful initializer, and no didSet observer, will side effects be triggered even if the first access to the property is a set?

It wouldn't have to. Attaching a willSet or didSet with the current semantics fundamentally requires a get of the underlying property implementation to prepare the old value, but an unobserved set doesn't need to.

2 Likes