[swift-evolution] [Proposal] Property behaviors

Félix Cloutier felixcca at yahoo.ca
Thu Jan 14 14:31:02 CST 2016

Joe, your idea for initializer as an accessor makes sense to me. Also, it seems that if resettable's initializer isn't delayed, we don't need the redundancy since it can set the base value from its own init:

> public var behavior resettable /* whatever goes here */ {
> 	eager accessor resetValue(): Value
> 	var value: Value = resetValue()
> }
> var [resettable] foo: Int { resetValue { return 42 } }

Even if I made it up just to support this case, I think that allowing `eager` and `delayed` on accessors might be a good idea. Right now, there appears to be no way to enforce that observed's willSet and didSet do not fire during property initialization. Marking them "delayed" could mean that.

I would support using "initializer" as a special accessor name that refers to the initializer value of the property (parsed as an autoclosure, mapping to whatever behaviors use behind the scenes). Having "delayed accessor"/"eager accessor" in front of it would make it much less magical in my opinion.

> public var behavior resettable /* whatever goes here */ {
> 	eager accessor initializer(): Value
> 	var value: Value = initializer()
> }
> var [resettable] foo: Int = 42

Chiming in with plx:

> ## Request: Declared-Property-Name
> If possible, a property analogous to `self` / `parent` / etc. getting at a behavior’s concrete “declared-name” would be amazing, although I know it’s not quite that easy, either (see @objc questions later).

I also think that this is an interesting idea. In fact, when reflection details are better specified (I think that it's in scope for Swift 3, right?), I think that behaviors should have access to the property's "mirror".

> ## Semantics: Overrides + Behaviors
> I think this is probably specified somewhere and I just don’t understand it, but I need to ask: how do overrides work for things like the following example:

Just like right now, I think that behaviors should be completely opaque to subclasses. This means you can't alter their behavior (unless they do a virtual call) and you're possibly not even aware that they have behaviors attached.

> …but if you “expand” what happens within these behaviors, once you have multiple such behaviors in a chain (e.g. `[redraw, invalidateSize]`) you will of course have one `!=` comparison per behavior. Note that although, in this case, `!=` is hopefully not too expensive, you can also consider it as a proxy here for other, possibly-expensive operations.

My personal hope is that the accessors will compose and optimize as nicely as short private funcs. I wonder how that would play out with behaviors taken from other modules though.

> ## ObjC Interaction

I think that this is an issue with @objc. I agree that it should get the name right for boolean properties.

Now going back to a warning when a behavior can alter the property without other behaviors noticing.

We have a pretty small sample size of behaviors, but I predict that it will always be a problem when a property value is set without the whole chain being aware of it. For instance, [resettable, observed] is as much a problem as [resettable, backedByJSON]. Using resettable's reset method bypasses behavior that was deemed useful (or even necessary) by the developer in these two cases. In fact, I would like to challenge you to think of a behavior B with a setter, in a chain [resettable, B], where `reset` bypassing B's setter is what the developer intends.

I think that either one of these should be implemented:

warn when using a mutating function on a behavior when "outer behaviors" have setters;
ensure that mutating functions send their result value down the behavior chain like a normal assignment (not sure how feasible this is with behaviors that have state).

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160114/38a96124/attachment.html>

More information about the swift-evolution mailing list