<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jan 15, 2016, at 8:42 AM, plx via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">One more “how will this work?” question: optionals.</div><div class=""><br class=""></div><div class="">Specifically, consider something like this:</div><div class=""><br class=""></div><div class="">// annoyingly-long protocol:</div><div class="">protocol ControlExchanging {</div><div class="">&nbsp; typealias Context</div><div class="">&nbsp; func willTakeControlFrom(other: Self?, context: Context)</div><div class="">&nbsp; func didTakeControlFrom(other: Self?, context: Context)</div><div class="">&nbsp;</div><div class="">&nbsp; func takeControl(context: Context)</div><div class="">&nbsp; func cedeControl(context: Context)</div><div class="">&nbsp;&nbsp;</div><div class="">&nbsp; func willCedeControlTo(other: Self?, context: Context)</div><div class="">&nbsp; func didCedeControlTo(other: Self?, context: Context)</div><div class="">}</div><div class=""><br class=""></div><div class="">var behavior exchangeState&lt;Value:ControlExchanging where Self:Value.Context&gt; : Value {</div><div class="">&nbsp; var value: Value</div><div class="">&nbsp; // here:</div><div class="">&nbsp; set {&nbsp;</div><div class="">&nbsp; &nbsp; let oldValue = value</div><div class="">&nbsp; &nbsp; // boilerplate-choreography begins:</div><div class="">&nbsp; &nbsp; newValue.willTakeControlFrom(oldValue, context: self)</div><div class="">&nbsp; &nbsp;&nbsp;oldValue.willCedeControlTo(newValue, context: self)</div><div class="">&nbsp; &nbsp; oldValue.cedeControl(self)</div><div class="">&nbsp; &nbsp; value = newValue</div><div class="">&nbsp; &nbsp; newValue.takeControl(self)</div><div class="">&nbsp; &nbsp; oldValue.didCedeControlTo(newValue, context: self)</div><div class="">&nbsp; &nbsp; newValue.didTakeControlFrom(oldValue, context: self)</div><div class="">&nbsp; }</div><div class="">}</div><div class=""><br class=""></div><div class="">// numerous extraneous details omitted:</div><div class="">class GenericSwitchboard&lt;Delegate:ControlExchanging were Delegate.Context == Self&gt; {</div><div class=""><br class=""></div><div class="">&nbsp; private(set) weak var [exchangeControl] delegate: Delegate? = nil</div><div class=""><br class=""></div><div class="">}</div><div class=""><br class=""></div><div class="">…which presumably won’t actually work unless I’ve either:</div><div class=""><br class=""></div><div class="">- added an additional implementation that’s typed-as `Value?`&nbsp;</div><div class="">- added a conditional-conformance for `ControlExchanging` to `Optional` (easy, but boilerplate)</div><div class=""><br class=""></div><div class="">….both of which are workable, neither of which feels optimal (and for the latter, consider also that in many cases such conformances may generally be undesirable).</div><div class=""><br class=""></div><div class="">Is there a trick/detail I’m missing here?</div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Jan 14, 2016, at 4:05 PM, Joe Groff &lt;<a href="mailto:jgroff@apple.com" class="">jgroff@apple.com</a>&gt; wrote:</div><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><div class="">Good point. Longer behavior compositions are something to consider. If behaviors have dedicated declarations instead of being applications of plain types or functions, it also becomes more reasonable to let them be used as attributes by themselves:</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">@mainThread @resettable @logged @changeObserved</div></div><div class=""><div class="">public var foo: Int { ... }</div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">I shied away from that design originally because it would be problematic to pollute the attribute namespace with potentially every function and/or type. That's less of a problem with this design.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">I still like the aesthetics of your design better (until maybe when things get too long).</div><div class=""><br class=""></div><div class="">It might be a good general policy for proposals with syntax changes to always include at least one “heavy-duty/extreme” example.</div><div class=""><br class=""></div><div class="">Another argument in favor of a different positioning: it makes these kinds of things easier to write:</div><div class=""><br class=""></div><div class="">@resettable @changeObserved</div><div class="">#if DEBUG</div><div class="">@mainThread @onlyAfterViewLoaded @logged&nbsp;</div><div class="">#endif</div><div class=""><br class=""></div><div class="">…(which may or may not be a good thing).</div></div></div></div></blockquote><div><br class=""></div><div>Would it be possible to move the "behavior list” prior to decl modifiers without needing to use attributes? &nbsp;The square brackets might not work in that case but maybe something else? &nbsp;</div><div><br class=""></div><div>I like the positioning but don’t like all the @ sigils and the fact that the behaviors would be potentially intermixed with other attributes. &nbsp;I also like that the square brackets in property declaration syntax makes it very clear when behaviors are involved.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class=""><div class="">## Request: Declared-Property-Name<br class=""><br class="">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).<br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">That's definitely an interesting extension to consider. I think it can be separated from the core proposal, though.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Agreed it is an extension; consider it in the spirit of “if a bunch of other such things get added, perhaps this should be too”.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="">## Semantics: Overrides + Behaviors<br class=""><br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">I would expect each override's [changeObserved] behavior to wrap the previous override, as happens if you override with `didSet`/`willSet` today. You raise the interesting question of what happens with the behavior names, since you do end up with two same-named behaviors applied at different times. That potentially requires deeper qualification by type; if we use Tal's suggested `.[behavior]` qualification syntax, you could refer to `.[BaseView.changeObserved]` and `.[RefinedView.changeObserved]` if you needed to.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">The behavior is what I’d expect, but it seems that that behavior will be an occasional source of subtle bugs in scenarios like this:</div><div class=""><br class=""></div><div class="">class Simple : Synchronizing {</div><div class="">&nbsp; &nbsp;var [changeObserved,synchronized] delicate: Delicate</div><div class="">}</div><div class=""><br class=""></div><div class="">class Fancy : Simple {</div><div class="">&nbsp; override var [changeObserved] delicate: Delicate {</div><div class="">&nbsp; &nbsp; willSet { /* consider timing vis-a-vis base's `synchronized` */ }</div><div class="">&nbsp; &nbsp; didSet { /* consider timing vis-a-vis base's `synchronized` */ }</div><div class="">&nbsp; }</div><div class="">}</div><div class=""><br class=""></div><div class="">…but I’m note sure there’s an easy way to make property behaviors flexible-enough to solve this problem purely at the property-behavior level; especially when it is easy in this sort of circumstance (and arguably better) to just write appropriate hooks into your class, and override from there.</div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="">## Semantics: Redundancy/“Static” Parameterization<br class=""><br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">It seems to me you could factor at least some of this boilerplate into a behavior, reducing it to:</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">var [invalidate] foo: String { invalidates { return [.Display, .ContentSize] } }</div></div></blockquote><div class=""><br class=""></div><div class="">Brent mentioned in the other thread about modeling `lazy` with an accessor some possibilities to whittle this down further, by allowing for implicit single-expression return in accessors, and inferring behaviors from accessor names:</div><div class=""><br class=""></div><div class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class=""><div class="">var foo: String { invalidates { [.Display, .ContentSize] } }</div></div></blockquote></div></div></div></blockquote><div class=""><br class=""></div><div class="">That’s a really nice trick and makes this a proposal a lot more feature-complete for me than I had realized, particularly if the implicit-return suggestion is taken.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><br class=""></div></div></blockquote></div><div class=""><blockquote type="cite" class=""><div class=""><div class="">## ObjC Interaction<br class=""><br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">You could potentially declare another @objc property that forwards to the stored property, though that's even less ideal of course:</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class="">var permitted: Bool</div><div class="">private var _objcPermitted: Bool {</div><div class="">&nbsp; @objc(isPermitted) get { return _permitted }</div><div class="">&nbsp; @objc(setPermitted:) set { _permitted = newValue }</div><div class="">}</div></div></blockquote><div class=""><br class=""></div><div class="">Behaviors definitely exacerbate this issue, since you have more interesting properties without native get/set accessors that you may want to control the ObjC interface for. The private @objc trick above at least still works.</div></div></div></blockquote><div class=""><br class=""></div><div class="">That’s another really nice way to do it. But, I’ll take this reply to mean an improvement to @objc-renaming is independent of this proposal, which is fine.</div><div class=""><br class=""></div><div class="">Overall this revision of the proposal is looking really nice.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">-Joe</div><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div class=""><br class="">On the one hand, this proposal doesn’t seem to change this situation.<br class=""><br class="">On the other hand, if it can be changed, this seems like a reasonable time/place to do it.<br class=""><br class="">That’s it for the moment.<br class=""><br class="">With this proposal it seems like a really nice feature to have.<br class=""><br class=""><blockquote type="cite" class="">On Jan 13, 2016, at 8:04 PM, Joe Groff &lt;<a href="mailto:jgroff@apple.com" class="">jgroff@apple.com</a>&gt; wrote:<br class=""><br class=""><br class=""><blockquote type="cite" class="">On Jan 13, 2016, at 5:12 PM, plx via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""><br class="">Quick Q1: is it the case that `var behavior redrawing&lt;Value where Self:UIView&gt; : Value { … } ` would work or no? I’d assume so, but I don’t think there are any examples with a non-protocol constraint on `Self`, making it hard to tell at a glance.<br class=""></blockquote><br class="">Yeah, you should be able to use arbitrary generic constraints.<br class=""><br class=""><blockquote type="cite" class=""><br class="">Quick Q2: is there anything you can do in this scenario:<br class=""><br class="">// w/in some behavior:<br class="">mutating func silentlySet(value: Value) {<br class="">value = value // &lt;- probably not going to work<br class="">self.value = value // &lt;- not right either, `self` is the behavior’s owner, right?<br class="">}<br class=""><br class="">…other than change the argument name to avoid conflict?<br class=""></blockquote><br class="">I thought I mentioned this in the proposal—you could use `behaviorName.value` to qualify a reference to the behavior's members within the behavior.<br class=""><br class=""><blockquote type="cite" class=""><br class="">Remark: it definitely feels a bit odd to be using both `Self` and `self` to mean something that’s neither consistent with the rest of the language nor, really, to mean `Self` (or `self`). <br class=""><br class="">I get not wanting new keywords, but this feels like it could be an economy too far; perhaps I’m misunderstanding some aspect of how it’s meant to work.<br class=""></blockquote><br class="">I'm not totally comfortable with it either. It at least corresponds to the notion of `self` you'd get if you'd coded a property by hand within its enclosing type, so the meaning might be useful for refactoring code out of concrete property implementations into behavior templates.<br class=""><br class="">-Joe<br class=""></blockquote><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></div></blockquote></div><br class=""></div></div></blockquote></div><br class="">
<img src="https://u2002410.ct.sendgrid.net/wf/open?upn=eLFMrKDT8iBxZ-2Fbnk-2BZqvSchNN-2FvYXdceA0T7VxwkAcVbwTGOTKvOWT2Ece3UstIHLvNK9zULZtjT6nCkCxSqNonQ83i1uStlxA8Et071RQ-2BJaoPHg8yuV-2F2unoE1Ane20EY7MzrOvmJy-2FW-2BwutjRTR74VVn2xyRimhmFoarvThFNg-2FTGARnqZdtWN6-2B7SaWbM48lmtV2ftuaUv5kORa0oMUgxWWhsB4pG-2B-2B6zc-2BLdk-3D" alt="" width="1" height="1" border="0" style="height:1px !important;width:1px !important;border-width:0 !important;margin-top:0 !important;margin-bottom:0 !important;margin-right:0 !important;margin-left:0 !important;padding-top:0 !important;padding-bottom:0 !important;padding-right:0 !important;padding-left:0 !important;" class="">
</div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>