<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 14, 2016, at 11:33 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=""><div class="">Thanks for the earlier feedback (you did mention how to resolve reference ambiguity).<br class=""><br class="">After re-reading it this is a really nice proposal overall. Even in it’s current state it is a huge upgrade, and could lead to a huge productivity / implementation-quality upgrade in application code.<br class=""><br class="">I do have a bunch of questions, though.<br class=""><br class="">## Syntax: “In the Large”<br class=""><br class="">One thing that does worry me is readability in real-world variable declarations; I agree that `@behavior(lazy)` is clunky in the small, but in the large the current syntax is questionable:<br class=""><br class="">class SomeView : UIView {<br class=""><br class=""> &nbsp;@IBInspectable<br class=""> &nbsp;&nbsp;public internal(set) weak var [mainThread,resettable,logged,changeObserved] contentAreaInsets: UIEdgeInsets = UIEdgeInsetsZero {<br class=""> &nbsp;&nbsp;&nbsp;logName { “contentAreaInsets” } // &lt;- see note later, btw<br class=""> &nbsp;&nbsp;&nbsp;didChange { setNeedsUpdateConstraints() }<br class=""> &nbsp;}<br class=""><br class="">}<br class=""><br class="">…which is admittedly an extreme example, but it illustrates the point.<br class=""><br class="">The below is definitely worse in the small, but feels better in the large:<br class=""><br class="">class SomeView : UIView {<br class=""><br class=""> &nbsp;@IBInspectable<br class=""> &nbsp;@behavior(mainThread,resettable,logged,changeObserved) <br class=""> &nbsp;public internal(set) weak var contentAreaInsets: UIEdgeInsets = UIEdgeInsetsZero {<br class=""> &nbsp;&nbsp;&nbsp;logName { “contentAreaInsets” } // &lt;- see note later, btw<br class=""> &nbsp;&nbsp;&nbsp;didChange { setNeedsUpdateConstraints() }<br class=""> &nbsp;}<br class=""><br class="">}<br class=""><br class="">…(I could add line breaks in the first one, but a line break anywhere between the `var` and its the name seems odd).<br class=""><br class="">To be clear, I am not suggesting the above syntax as-is; I am more trying to make sure some consideration is “how does this look with longer behavior lists”, since all the examples in the proposal are for “nice” cases.<br class=""><br class="">Putting the behavior-list after `var` but before the name and type seems unfortunate once you want to add a line-break in there.<br class=""></div></div></blockquote><div><br class=""></div><div>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><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div>@mainThread @resettable @logged @changeObserved</div></div><div><div>public var foo: Int { ... }</div></div></blockquote><div><div><br class=""></div><div>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><br 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><br class=""></div><div>That's definitely an interesting extension to consider. I think it can be separated from the core proposal, though.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="">## Semantics: Overrides + Behaviors<br class=""><br class="">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:<br class=""><br class="">class BaseView : UIView {<br class=""><br class=""> &nbsp;var [changeObserved] text: String {<br class=""> &nbsp;&nbsp;&nbsp;didChange { setNeedsLayout() }<br class=""> &nbsp;}<br class=""><br class="">}<br class=""><br class="">class RefinedView : BaseView {<br class=""><br class=""> &nbsp;// is this right? (recall property is already `changeObserved` in parent):<br class=""> &nbsp;override var text: String {<br class=""> &nbsp;&nbsp;&nbsp;didChange { invalidateIntrinsicContentSize() } <br class=""> &nbsp;&nbsp;&nbsp;// ^ does parent’s didChange get called also? can I control that?<br class=""> &nbsp;&nbsp;&nbsp;// ^ when is this override called? when is the parent called (if it is)?<br class=""> &nbsp;}<br class=""><br class=""> &nbsp;// or is this right? (needing to add another `changeObserved` here?)<br class=""> &nbsp;override var [changeObserved] text: String {<br class=""> &nbsp;&nbsp;&nbsp;didChange { invalidateIntrinsicContentSize() }<br class=""> &nbsp;&nbsp;&nbsp;// ^ does parent’s didChange get called also? can I control that?<br class=""> &nbsp;&nbsp;&nbsp;// ^ when is this override called? when is the parent called (if it is)?<br class=""> &nbsp;}<br class=""><br class="">}<br class=""><br class="">…I’m really not sure which of the above is more reasonable. <br class=""><br class="">The first variant would seem to have confusing timing (when do the calls happen relative to each other and to other behaviors)?<br class=""><br class="">The other one seems to introduce a new, identically-named behavior, which seems like it’d lead to ambiguity if you had to use behavior methods/behavior properties.<br class=""></div></div></blockquote><div><br class=""></div><div>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><br class=""><blockquote type="cite" class=""><div class=""><div class="">## Semantics: Redundancy/“Static” Parameterization<br class=""><br class="">This is an extended example, but it sort-of has to be to illustrate the concern.<br class=""><br class="">Suppose we wanted to define a bunch of behaviors useful for use on UIView. I’ll provide a few examples, including just the `set` logic to keep it as short as possible:<br class=""><br class="">// goal: `redraw` automatically calls `setNeedsDisplay()` when necessary:<br class="">var behavior redraw&lt;Value:Equatable where Self:UIView&gt; : Value {<br class=""> &nbsp;set { <br class=""> &nbsp;&nbsp;&nbsp;if newValue != value {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value = newValue<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.setNeedsDisplay()<br class=""> &nbsp;&nbsp;&nbsp;}<br class=""> &nbsp;}<br class="">}<br class=""><br class="">// goal: `invalidateSize` automatically calls `invalidateIntrinsicContentSize()` when necessary:<br class="">var behavior invalidateSize&lt;Value:Equatable where Self:UIView&gt; : Value {<br class=""> &nbsp;set { <br class=""> &nbsp;&nbsp;&nbsp;if newValue != value {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value = newValue<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.invalidateIntrinsicContentSize()<br class=""> &nbsp;&nbsp;&nbsp;}<br class=""> &nbsp;}<br class="">}<br class=""><br class="">…(and you can consider also `relayout`, `updateConstraints`, `updateFocus`, accessibility utilities, and so on…).<br class=""><br class="">With all those in hand, we arrive at something IMHO really nice and self-documenting:<br class=""><br class="">class CustomDrawnView : UIView {<br class=""><br class=""> &nbsp;// pure-redrawing:<br class=""> &nbsp;var [redraw] strokeWidth: CGFloat<br class=""> &nbsp;var [redraw] outlineWidth: CGFloat<br class=""> &nbsp;var [redraw] strokeColor: UIColor<br class=""> &nbsp;var [redraw] outlineColor: UIColor<br class=""><br class=""> &nbsp;// also size-impacting:<br class=""> &nbsp;var [redraw, invalidateSize] iconPath: UIBezierPath<br class=""> &nbsp;var [redraw, invalidateSize] captionText: String<br class=""> &nbsp;var [redraw, invalidateSize] verticalSpace: CGFloat<br class=""><br class="">}<br class=""><br class="">…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.<br class=""><br class="">On the one hand, it seems like it ought to be possible to do better here — e.g., do a single such check, not one per behavior — but on the other hand, it seems hard to augment the proposal to make it possible w/out also making it much more complex than it already is.<br class=""><br class="">EG: the best hope from a readability standpoint might be something like this behavior:<br class=""><br class="">var behavior invalidate&lt;Value:Equatable where Self:UIView&gt; {<br class=""> &nbsp;// `parameter` here is new syntax; explanation below<br class=""> &nbsp;parameter display: Bool = false<br class=""> &nbsp;parameter intrinsicSize: Bool = false<br class=""><br class=""> &nbsp;// as-before:<br class=""> &nbsp;var value: Value<br class=""><br class=""> &nbsp;// `get` omitted: <br class=""> &nbsp;set {<br class=""> &nbsp;&nbsp;&nbsp;if newValue != value {<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value = newValue<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if display { self.setNeedsDisplay() }<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if intrinsicSize { self.invalidateIntrinsicContentSize() }<br class=""> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// also imagine constraints, layout, etc.<br class=""> &nbsp;&nbsp;&nbsp;}<br class=""> &nbsp;}<br class="">}<br class=""><br class="">…but to achieve that “omnibus” capability you’d need a lot of flags, each of which:<br class=""><br class="">- needs to get set somehow (without terrible syntax)<br class="">- needs to get “stored" somehow (without bloating the behaviors, if possible)<br class=""><br class="">Syntax to set the flags seems awkward at best:<br class=""><br class="">// this seems close to ideal for such parameters:<br class="">var [invalidate(display,intrinsicSize)] iconPath: UIBezierPath<br class=""><br class="">// but this seems the best-achievable option w/out dedicated compiler magic:<br class="">var [invalidate(display=true, intrinsicSize=true)] iconPath: UIBezierPath<br class=""><br class="">…and at least to my eyes that "best-achievable syntax" isn’t all that great, anymore.<br class=""><br class="">Likewise you’d need some way to actually store those parameters, presumably *not* as ordinary stored fields — that’s going to bloat the behaviors! — but as some new thing, whence the new `parameter` keyword.<br class=""><br class="">Between that and the naming/parameter-passing, it feels like a big ask, probably too big.<br class=""><br class="">FWIW, for sake of comparison, this seems to be about the best you can do under the current proposal:<br class=""><br class="">class CustomDrawnView : UIView {<br class=""><br class=""> &nbsp;// pure-redrawing:<br class=""> &nbsp;var [changeObserved] strokeWidth: CGFloat {<br class=""> &nbsp;&nbsp;&nbsp;didChange { invalidate(.Display) }<br class=""> &nbsp;}<br class=""><br class=""> &nbsp;var [changeObserved] outlineWidth: CGFloat {<br class=""> &nbsp;&nbsp;&nbsp;didChange { invalidate(.Display) }<br class=""> &nbsp;}<br class=""><br class=""> &nbsp;var [changeObserved] strokeColor: UIColor {<br class=""> &nbsp;&nbsp;&nbsp;didChange { invalidate(.Display) }<br class=""> &nbsp;}<br class=""><br class=""> &nbsp;var [changeObserved] outlineColor: UIColor {<br class=""> &nbsp;&nbsp;&nbsp;didChange { invalidate(.Display) }<br class=""> &nbsp;}<br class=""><br class=""> &nbsp;// also size-impacting:<br class=""> &nbsp;var [changeObserved] iconPath: UIBezierPath {<br class=""> &nbsp;&nbsp;&nbsp;didChange { invalidate([.Display, .IntrinsicContentSize]) }<br class=""> &nbsp;}<br class=""><br class=""> &nbsp;var [changeObserved] captionText: String {<br class=""> &nbsp;&nbsp;&nbsp;didChange { invalidate([.Display, .IntrinsicContentSize]) }<br class=""> &nbsp;}<br class=""><br class=""> &nbsp;var [changeObserved] verticalSpace: CGFloat {<br class=""> &nbsp;&nbsp;&nbsp;didChange { invalidate([.Display, .IntrinsicContentSize]) }<br class=""> &nbsp;}<br class=""><br class="">}<br class=""><br class="">…where `invalidate` is taking some bitmask/option-set and then calling the appropriate view methods.<br class=""><br class="">This isn’t terrible, it’s just nowhere near what it might be under this proposal.<br class=""><br class="">I also think it’s perfectly reasonable to see the above and decide the likely complexity of a solution probably outweighs whatever gains it might bring; I’m just bringing it up in hopes there might be an easy way to have most of the cake and also eat most of the cake.<br class=""></div></div></blockquote><div><br class=""></div><div>It seems to me you could factor at least some of this boilerplate into a behavior, reducing it to:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div>var [invalidate] foo: String { invalidates { return [.Display, .ContentSize] } }</div></div></blockquote><div><br class=""></div><div>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><br class=""></div><div><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div><div>var foo: String { invalidates { [.Display, .ContentSize] } }</div><div class=""><br class=""></div></div></blockquote></div><div><blockquote type="cite" class=""><div class=""><div class="">## ObjC Interaction<br class=""><br class="">One thing I am not sure about is how this interacts with @objc annotations. <br class=""><br class="">First, my assumption is that, as today, property behaviors and @objc-visibilty are essentially orthogonal (don’t really impact each other). This doesn’t seem to be stated explicitly anywhere, and it would be preserving the status quo, but it’s worth confirming just to be sure.<br class=""><br class="">Secondly, right now one of the language’s minor warts is you can’t really get proper objective-c property names on some read-write properties without some doing.<br class=""><br class="">You can either do this:<br class=""><br class="">class Foo: NSObject {<br class=""> &nbsp;@objc(isPermitted)<br class=""> &nbsp;var permitted: Bool<br class="">}<br class=""><br class="">…which gets you `isPermitted` (good) and `setIsPermitted:` (not ideal), or you can do this:<br class=""><br class="">class Foo: NSObject {<br class=""><br class=""> &nbsp;@nonobjc // maximize chances of efficiency<br class=""> &nbsp;private final var _permitted: Bool<br class=""><br class=""> &nbsp;var permitted: Bool {<br class=""> &nbsp;&nbsp;&nbsp;@objc(isPermitted) get { return _permitted }<br class=""> &nbsp;&nbsp;&nbsp;@objc(setPermitted:) set { _permitted = newValue }<br class=""> &nbsp;}<br class=""><br class="">}<br class=""><br class="">…which gets the right Objective-C names but is quite clunky.<br class=""><br class="">What you can’t do is this:<br class=""><br class="">class Foo: NSObject {<br class=""> &nbsp;var permitted: Bool {<br class=""> &nbsp;&nbsp;@objc(isPermitted) get, // just rename<br class=""> &nbsp;&nbsp;@objc(setPermitted:) set // just rename <br class="">}<br class=""><br class="">…at least not to my knowledge; if there’s a trick I don’t know it.<br class=""></div></div></blockquote><div><br class=""></div><div>You could potentially declare another @objc property that forwards to the stored property, though that's even less ideal of course:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div>var permitted: Bool</div><div>private var _objcPermitted: Bool {</div><div>&nbsp; @objc(isPermitted) get { return _permitted }</div><div>&nbsp; @objc(setPermitted:) set { _permitted = newValue }</div><div>}</div></div></blockquote><div><br class=""></div><div>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><br class=""></div><div>-Joe</div><div><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="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></div></blockquote></div><br class=""></body></html>