<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=""><div><blockquote type="cite" class=""><div class="">On Jan 20, 2016, at 9:19 AM, 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=""><div class=""><blockquote type="cite" class=""><div class="">On Jan 19, 2016, at 6:38 PM, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class="">On Jan 19, 2016, at 5:47 PM, Joe Groff &lt;<a href="mailto:jgroff@apple.com" class="">jgroff@apple.com</a>&gt; wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class="">On Jan 19, 2016, at 4:28 PM, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class=""><div class="">On Jan 19, 2016, at 3:10 PM, Joe Groff &lt;<a href="mailto:jgroff@apple.com" class="">jgroff@apple.com</a>&gt; wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class="">On Jan 19, 2016, at 2:46 PM, John McCall &lt;<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class="">On Jan 13, 2016, at 2:07 PM, Joe Groff via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><div class=""><div class="">Thanks everyone for the first round of feedback on my behaviors proposal. I've revised it with the following changes:<br class=""><br class="">- Instead of relying on mapping behaviors to function or type member lookup, I've introduced a new purpose-built 'var behavior' declaration, which declares the accessor and initializer requirements and provides the storage and behavior methods of the property. I think this gives a clearer design for authoring behaviors, and allows for a more efficient and flexible implementation model.<br class="">- I've backed off from trying to include 'let' behaviors. As many of you noted, it's better to tackle immutable computed properties more holistically than to try to backdoor them in.<br class="">- I suggest changing the declaration syntax to use a behavior to square brackets—'var [behavior] foo'—which avoids ambiguity with destructuring 'var' bindings, and also works with future candidates for behavior decoration, particularly `subscript`.<br class=""></div></div></blockquote><div class=""><br class=""></div></div>Syntax comments:<div class=""><br class=""></div><div class="">I still think these feel attribute-like to me, but if we’re not just going to use @lazy — and I agree that that does have some problems —I’m fine with [lazy].<br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">I'm OK with using attribute syntax alongside the declaration approach.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><br class=""></div><div class="">"var behavior" is really weird to me, and the &lt;T&gt; doesn’t seem to fit and is pretty redundant in the common case. &nbsp;How about this:</div></div><div class=""><br class=""></div><div class=""><font face="Menlo" class="">&nbsp;&nbsp;"behavior" var-or-let "[" identifier-list "]" (identifier |&nbsp;</font><span class="" style="font-family: Menlo;">"</span><font face="Menlo" class="">_</font><span class="" style="font-family: Menlo;">")</span><span class="" style="font-family: Menlo;">&nbsp;":" identifier (</span><span class="" style="font-family: Menlo;">"="</span><span class="" style="font-family: Menlo;">&nbsp;</span><span class="" style="font-family: Menlo;">identifier)?&nbsp;</span><span class="" style="font-family: Menlo;">("where" generic-requirement-list)?</span></div><div class=""><br class=""></div><div class="">So, for example,</div><div class=""><font face="Menlo" class="">&nbsp; behavior var [lazy] _ : T where T : IntegerLiteralConvertible { … }</font></div><div class=""><br class=""></div><div class="">This is definitely taking the idea of “this is basically a macro” and running with it. &nbsp;Think of the stuff between “behavior” and the optional “where” as being a pattern for the declaration. &nbsp;So this pattern would match:</div><div class=""><font face="Menlo" class="">&nbsp; var [lazy] x: Int</font></div><div class="">but not:</div><div class=""><font face="Menlo" class="">&nbsp; let [lazy] x: Int</font></div><div class="">or:</div><div class=""><font face="Menlo" class="">&nbsp; var [lazy] x : Int = foo()</font></div></div></div></blockquote><div class=""><br class=""></div><div class="">Good idea, I like this approach. However:</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">The behavior list has to match exactly (or maybe as sets?).</div></div></div></blockquote><div class=""><br class=""></div><div class="">Are you saying that there would be no ad-hoc composition of behaviors? This seems to imply that you'd need to implement every valid combination of behaviors by hand. That's a defensible position, given that it's easy to compose behaviors like "synchronized" in the wrong order, but significantly stifles behaviors like didSet/willSet that are more likely to be order-agnostic.</div></div></div></div></blockquote><div class=""><br class=""></div>My first instinct is to say that ad-hoc composition is too treacherous to include in the first model, yeah.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">I like the idea of having a model that works for literally everything that’s not pure-computed or pure-stored, but it seems tolerable to continue to build in things like willSet / didSet if it significantly simplifies the problem. &nbsp;willSet / didSet have some pretty custom behavior and dependencies on the container. &nbsp;OTOH, maybe that kind of thing is a core requirement for some of the stuff we’re thinking of doing.</div></div></blockquote><div class=""><br class=""></div><div class="">I think you can define a reasonable facsimile of willSet/didSet under my proposal, but I'm willing to believe there are edge cases I'm missing. What sort of custom behavior do you have in mind?</div></div></div></div></blockquote><div class=""><br class=""></div>Well, for one, we only load the old value if the didSet is actually declared. &nbsp;There’s also the longstanding idea — apparently still not implemented — that we’d only do so if didSet actually used the old value. &nbsp;The ideal result here really needs macro metaprogramming, I think, unless you’re going to get very sophisticated about accessor declarations.</div></div></blockquote><div class=""><br class=""></div><div class="">One of the nice things about last month's function-based proposal was that it allowed overloading a behavior, which could allow for the right variation of behavior to be chosen given different accessors. We could possibly make this work for behavior decls too, treating the set of accessor requirements as the "signature" of a behavior. Even without overloading, we could separate 'didSet' and 'willSet' into separate behaviors that can be optionally composed.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">One of my worries about this proposal in general is that you’ve listed out half-a-dozen different uses and every single one seems to require a new twist on the core semantics.</div></div></blockquote><div class=""><br class=""></div><div class="">Yeah, that worries me too. I think though that these twists are sugar over the basic functionality, though. Fundamentally we want a way to factor out one or both of two things:</div><div class=""><br class=""></div><div class="">- The storage that gets instantiated for a property, and/or</div><div class="">- The get/materializeForSet/set implementations that get run for a property.</div><div class=""><br class=""></div><div class="">Most of the accessor and initializer complexity is essentially sugar for parameterizing the behavior. Many in this thread have proposed allowing direct parameterization of the behavior like 'var [behavior(param)]'; if the behavior could allocate and initialize static storage to capture those parameters, you could do everything you can with accessors or bound initializers (modulo "only" syntactic things like type-inferencing properties from initializer expressions).</div></div></div></div></blockquote><div><br class=""></div>That’s reasonable, but it’s definitely treading on future directions for hygienic macro definition. &nbsp;I think the current syntax leaves plenty of room for that.</div><div><br class=""></div><div>It’d be a pretty awkward way of doing willSet / didSet, though.</div><div><br class=""></div><div>John.</div><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><div class="">-Joe</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">John.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><br class=""></div><div class="">-Joe</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">The property name, if bound, expands to a string literal within the behavior.</div><div class=""><br class=""></div><div class="">The type name is always a generic parameter. &nbsp;This interferes with the ability to make a pattern that only matches a concrete type, but I think that’s okay.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Seems reasonable, since unconstrained behaviors are likely to be the 95% case. Being able to match concrete types is something we ought to be able solve uniformly with the same limitation on constrained extensions.</div></div></div></div></blockquote><div class=""><br class=""></div>Yeah.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">The initializer name, if bound, expands to the original expression within the behavior. &nbsp;Maybe it should be coerced to type T first? &nbsp;Not sure.</div></div></div></blockquote><br class=""></div><div class="">Yeah, JoeP brought up a good question about how 'var' type inference should work with initializer expressions. There are two possible models I can see:</div><div class=""><br class=""></div><div class="">- We infer the type of the initializer independent of any applied behaviors, and raise an error if the behavior can't be instantiated at the given type.</div><div class="">- We add generic constraints from the behavior declaration(s) to the contextual type of the initializer.</div><div class=""><br class=""></div><div class="">In support of the latter approach, 'weak' properties currently factor their Optional constraint into type inference ('weak var foo = Foo()' gives you a property of type Foo?), and 'weak' has been raised as a candidate for eventual behavior-ization. The downside, of course, is that with arbitrary user-defined behaviors with arbitrary generic constraints, there's yet another source of potential surprise if the type context of behaviors changes the type-checking of an expression.</div></div></div></blockquote><div class=""><br class=""></div>Yeah, especially because the initializer could be used in multiple places in the behavior. &nbsp;Coercing the initializer seems a lot less surprising.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">John.</div></div></blockquote></div></div></div></blockquote></div></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></body></html>