<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 19, 2016, at 2:46 PM, John McCall via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</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 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 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 style="font-family: Menlo;" class="">"</span><font face="Menlo" class="">_</font><span style="font-family: Menlo;" class="">")</span><span style="font-family: Menlo;" class="">&nbsp;":" identifier (</span><span style="font-family: Menlo;" class="">"="</span><span style="font-family: Menlo;" class="">&nbsp;</span><span style="font-family: Menlo;" class="">identifier)?&nbsp;</span><span style="font-family: Menlo;" class="">("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 class=""><br class=""></div><div class="">The behavior list has to match exactly (or maybe as sets?).</div><div class=""><br class=""></div><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 class=""><br class=""></div><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><div><br class=""></div>I feel like there are two possible implementation models here: type instantiation and member instantiation. &nbsp;The type instantiation model has the advantage of allowing generic programming over the complete lazy type, but probably means we end up creating a lot of redundant stuff, some of which we’d have trouble eliminating. &nbsp;The member instantiation model is tricky and more limiting in terms of what you can do polymorphically directly with behavior types, but (1) I don’t think that’s crucial and (2) it does seem implementable.<br class=""><div><br class=""></div></div>The member-instantiation model looks like this:<div class=""><br class=""></div><div class="">Conceptually, a behavior declaration creates a generic behavior value type:</div><div class="">&nbsp; struct [weak,lazy]&lt;T&gt; {</div><div class="">&nbsp; &nbsp; ...</div><div class="">&nbsp; }</div><div class=""><br class=""></div><div class="">That behavior declaration always contains an implicit “value” member:</div><div class="">&nbsp; var value : T {</div><div class="">&nbsp; &nbsp; ...</div><div class="">&nbsp; }</div><div class=""><br class=""></div><div class="">Any accessors in the behavior body are considered to be accessors of the value member. &nbsp;Everything else is just a member of the behavior type.</div><div class=""><br class=""></div><div class="">An expression within the main behavior declaration is “instantiated” if it refers to any of the bound macro parameters (other than the type T). &nbsp;A function body within the main behavior declaration is instantiated if:</div><div class="">&nbsp; - it contains an instantiated expression,</div><div class="">&nbsp; - it is an initializer, and the initializer expression of a stored property contains an instantiated expression,</div><div class="">&nbsp; - it uses a function within the main behavior declaration that is instantiated, or</div><div class="">&nbsp; - it uses an accessor within the main behavior declaration that is instantiated.</div><div class=""><br class=""></div><div class="">An instantiated member or accessor of the behavior type may not be used outside of the behavior body except as directly applied to a particular behavior object.</div><div class=""><br class=""></div><div class="">We can still separately type-check and even generate SIL for instantiated members. &nbsp;Type-checking works by saying that the property name is an opaque string literal and the initializer is an opaque r-value of type T; the type-checker would have to do the latter coercion for each use, but that seems better semantically and for type inference anyway. &nbsp;When an instantiated function was used from an uninstantiated context, SILGen would just create SIL builtins that fetch the name / initializer; instantiating would clone the body and replace those operations. &nbsp;The type checker would require that instantiated functions can only be used from appropriate contexts, and the SIL verifier and IRGen would do the same.</div><div class=""><br class=""></div><div class="">The behavior type must be nullary-initializable (possibly with an instantiated initializer). &nbsp;At the use site, the behavior is always expanded as:</div><div class="">&nbsp; var _foo_behavior = [weak,lazy]&lt;T&gt;()</div><div class=""><br class=""></div><div class="">I’m not quite sure how extensions should work with initializers, because what I described above naturally allows behaviors to be overloaded based on the presence/absence of the initializer. &nbsp;Either that’s disallowed, or you have to write:</div><div class="">&nbsp; extension var [weak,lazy] _ : T = _ { … }</div><div class="">to clarify that (1) you mean the behavior that allows an initializer but (2) you can’t actually use the initializer expression in your implementation, because the member-instantiation model definitely doesn’t support doing that.</div><div class=""><br class=""></div><div class="">John.</div></body></html>