<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 Dec 23, 2015, at 9:25 AM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.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=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">Hi Matthew,</div><div class=""><br class=""></div><div class="">I continue to really like the approach and direction. &nbsp;Here’s an attempt to respond to both of your responses, I hope this comes across somewhat coherent:</div></div></div></blockquote><div class=""><br class=""></div><div class="">Excellent, thanks! &nbsp;I have completed a third draft of the proposal. &nbsp;It may (probably does) still require further refinement but I believe it is another solid step forward.</div><div class=""><br class=""></div><div class="">Here’s the complete draft:&nbsp;<a href="https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md" class="">https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md</a></div><div class=""><br class=""></div><div class="">Here’s the commit diff in case that is more helpful:&nbsp;<a href="https://github.com/anandabits/swift-evolution/commit/8287b67569038000aa4231cc7725e5fbeb7fe8ce?short_path=f5ec377#diff-f5ec377f4782587684c5732547456b70" class="">https://github.com/anandabits/swift-evolution/commit/8287b67569038000aa4231cc7725e5fbeb7fe8ce?short_path=f5ec377#diff-f5ec377f4782587684c5732547456b70</a></div><div class=""><br class=""></div><div class="">Discussion on a couple of topics continues inline below as well.</div></div></div></div></blockquote><div><br class=""></div><div>Great, comments below:</div><div><br class=""></div><div>"memberwise initializer for us in some” -&gt; typo “use”</div><div>"elimintate the existing “ -&gt; typo “eliminate"</div><div><br class=""></div>"Sometimes properties that should be immutable are made mutable” -&gt; should be updated to reflect the new approach?</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=""><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="">There are two major problems:</div><div class=""><br class=""></div><div class="">Problem 1: supporting this would *prevent* us from allowing memberwise initializers to be public. &nbsp;A really important feature of the memberwise design is that it is “just sugar” and that people can write the initializer out long hand if needed (e.g. if they want to add or reorder members without breaking API). &nbsp;With your proposed design, I could write:</div><div class=""><br class=""></div><div class="">public class X {</div><div class="">&nbsp; let a = 42</div><div class="">&nbsp; public memberwise init(...) {}</div><div class="">}</div><div class=""><br class=""></div><div class="">and use it with: X(a: 17). &nbsp;However, there is no way in swift to write that initializer out longhand. &nbsp;This is a critical problem to me.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Maybe it wasn’t clear, but I was suggesting that this particular rule be changed for <b class="">all</b>&nbsp;initializers. &nbsp;That would have made it possible to write the initializer out longhand. &nbsp;But I have pulled that part of the proposal so it doesn’t matter now.&nbsp;</div></div></div></div></blockquote><div><br class=""></div><div>Sounds good thanks. &nbsp;Changing the initialization semantics for lets in general is something far more nuanced and should be discussed separately. &nbsp;The design we have now is carefully considered, and has already been refined from what shipped in Swift 1.0.</div><div><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 style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Problem 2: This can cause very surprising performance issues, because it forces the let property to be stored. &nbsp;With the previous example, it is a goal for us to be able to compile:</div><div class=""><br class=""></div><div class="">public class X {</div><div class="">&nbsp; let a = 42</div><div class="">}</div><div class=""><br class=""></div><div class="">into the equivalent of:</div><div class=""><br class=""></div><div class=""><div class="">public class X {</div><div class="">&nbsp; var a : Int { return 42 }</div><div class="">}</div></div><div class=""><br class=""></div><div class="">because people like to use local lets as manifest constants (avoiding “magic numbers”). &nbsp;With your proposal, we’d lose this capability, and we’d have to store them any time there is a memberwise initializer.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I would have never considered writing a type with an <i class="">instance</i>&nbsp;member with constant value that cannot be assigned a different value in the initializer as I would have considered it wasted space and possibly worthy of a compiler error. &nbsp;I would have written:</div><div class=""><br class=""></div><div class="">public class X {<br class="">&nbsp; static let a = 42<br class="">}<br class=""><br class=""></div><div class="">Clearly I was underestimating the optimizer! &nbsp;I can see value in the ability to refer to the member without a prefix. &nbsp;Given the (guaranteed?) optimization it definitely makes sense. &nbsp;</div></div></div></div></blockquote><div><br class=""></div><div>I understand, and I would have written the same. &nbsp;However, it has been pointed out to me numerous times that I only know to write that because I “know too much” about the implementation. &nbsp;It is also annoying that writing it as a static property would force you to write something like “X.a" instead of just “a".</div><div><br class=""></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 type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Neither of these problems apply to vars, which is why I think we can support vars in this model, but not lets.</div></div></div></blockquote><div class=""><br class=""></div><div class="">As you said you agree with the desire to support this behavior, maybe you would be comfortable with a different approach. &nbsp;Rather than using the initial value we could use an attribute:</div><div class=""><br class=""></div><div class="">public class X {<br class="">&nbsp; @default(42) let a<br class="">}</div><div class=""><br class=""></div><div class="">This would allow us to still support the desired memberwise initialization behavior without conflicting with the current “initial value” behavior. &nbsp;I’m have updated the proposal to specify the behavior this way. &nbsp;If you don’t like it let’s continue the discussion.</div><div class=""><br class=""></div><div class="">It could be called @default, @memberdefault, @memberwisedefault, etc. &nbsp;The name doesn’t really matter to me.</div></div></div></div></blockquote><div><br class=""></div><div>I’m not inclined to like an approach that requires magic attributes to be sprinkled around the code. &nbsp;The more attributes and annotations you have to add to your properties, the less the syntactic sugar of memberwise initializers are paying for themselves.</div><div><br class=""></div><div>I see that your new version introduces the @default attribute. &nbsp;I’d strongly suggest the same advice as before (I know I must sound monotonous :-) - please start your proposal minimal and straight-forward, by moving @default to the “possible future extensions” section. &nbsp;We can always add it later to build out the model if there is a strong need, but I’d rather see us roll out the next incremental step and learn from it before we do. &nbsp;That allows us to carefully consider how much each piece is adding and costing as independent entities.</div><div><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 style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><div class="">I understand, but it is a pure extension to the basic proposal. &nbsp;The proposal is complex enough as it is, so inessential parts should be split out for discussion and implementation. &nbsp;I’m not saying that we shouldn’t do @nomemberwise in (e.g.) the swift 3 timeframe, I’m saying that it should be a separate discussion informed by the design and implementation process of the base proposal.</div></div></div></div></div></div></div></blockquote><div class=""><br class=""></div><div class="">That makes sense. &nbsp;I have updated the proposal to reflect this. &nbsp;Incremental change, right? :)</div></div></div></div></blockquote><div><br class=""></div><div>Incremental is good!</div><div><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=""><div class=""><br class=""></div><div class="">I absolutely agree that the compiler should not be in the business of making a guess about what superclass initializer needs to be called! &nbsp;</div></div></div></div></blockquote><div><br class=""></div><div>Pwew, great!</div><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="">The example was intended to include a call to provide all of the arguments necessary to disambiguate prior to memberwise argument forwarding. &nbsp;In this case of the present example none are necessary. &nbsp;I am including the corrected example here and have also updated the proposal. &nbsp;It should have read like this:</div><div class=""><br class=""></div><div class=""><div class="highlight highlight-source-swift" style="box-sizing: border-box; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25px; background-color: rgb(255, 255, 255);"><pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; word-break: normal;" class=""><span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">class</span> Base {
    <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">let</span> baseProperty: <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">String</span>

    <span class="pl-c" style="box-sizing: border-box; color: rgb(150, 152, 150);">// user declares:</span>
    memberwise <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">init</span>(<span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">...</span>) {}
    <span class="pl-c" style="box-sizing: border-box; color: rgb(150, 152, 150);">// compiler synthesizes:</span>
    <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">init</span>(baseProperty: <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">String</span>) {
        <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">self</span><span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">.</span>baseProperty <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">=</span> baseProperty
    }
}
</pre></div></div></div></div></blockquote><div>Looks good so far.</div><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><div class="highlight highlight-source-swift" style="box-sizing: border-box; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; line-height: 25px; background-color: rgb(255, 255, 255);"><pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; margin-top: 0px; margin-bottom: 0px; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; word-break: normal;" class="">
<span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">class</span> Derived: Base {
    <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">let</span> derivedProperty: <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">Int</span>

    <span class="pl-c" style="box-sizing: border-box; color: rgb(150, 152, 150);">// user declares:</span>
    memberwise <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">init</span>(<span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">...</span>) { super.init(...) }
    <span class="pl-c" style="box-sizing: border-box; color: rgb(150, 152, 150);">// compiler synthesizes (adding forwarded memberwise parameters):</span>
    <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">init</span>(baseProperty: <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">String</span>, derivedProperty: <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 134, 179);">Int</span>) {
        <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">self</span><span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">.</span>derivedProperry <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">=</span> derivedProperty
        <span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">super</span><span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">.</span><span class="pl-k" style="box-sizing: border-box; color: rgb(167, 29, 93);">init</span>(baseProperty: baseProperty)
    }
}
</pre></div></div></div></div></blockquote><div>This I still have a concern with, in two ways:</div><div><br class=""></div><div>1) This still has tight coupling between the base and derived class. &nbsp;Properties in a based class are not knowable by a derived class in general (e.g. across module boundaries) and this directly runs afoul of our resilience plans. &nbsp;Specifically, across module boundaries, properties can change from stored to computed (or back) without breaking clients.</div><div><br class=""></div><div>2) You’re introducing another unnecessary feature "super.init(…)” which will have to be independently justified.&nbsp;</div><div><br class=""></div><div>I consider #1 a showstopper but, in any case, this is an orthogonal add-on to your base proposal, which can be considered independently as the base proposal rolls out. &nbsp;I’d strongly suggest dropping it from the first revision of the proposal. &nbsp;It can be added at any time if there is a compelling need. &nbsp;If/when we consider this, I’d suggest thinking about it in terms of a more general parameter forwarding feature, instead of something tied to memberwise initializers.</div><div><br class=""></div><div><br class=""></div><div>A related concern is the part of your proposal that supports memberwise initializers for convenience initializers. &nbsp;I think this should be dropped for a number of reasons:</div><div><br class=""></div><div>1) Again, it is a major problem for resilience, because convenience initializers (unlike designated ones) can be added to a type in an extension. &nbsp;That extension can be defined in another module, and it isn’t knowable it that module what stored properties a type has.</div><div><br class=""></div><div>2) Convenience initializers, by intent if not "by definition”, should not publish every little detail of a type. &nbsp;They are intended to be used as an additional non-canonical way to initialize a type. &nbsp;While I’m sure there are some exceptions, the ability to have a memberwise initializer doesn’t seem very core to them.</div><div><br class=""></div><div><br class=""></div><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="">I understand there also potentially resilience concerns around supporting inheritance. &nbsp;If you’re willing to dive into specifics I may (or may not) be able to find solutions. &nbsp;If I am not able to identify solutions, at least I have tried and understand the specific issues involved. &nbsp;:)</div></div></div></blockquote><div><br class=""></div><div>I’m definitely willing to explain, please let me know if the above makes sense or not.</div><blockquote type="cite" 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="">I personally don’t like inheritance very much and consider it a tool of last resort, but I do think it is best for a feature like flexible memberwise initialization in a language that offers inheritance should support it if at all possible.</div></div></div></blockquote><div><br class=""></div><div>Ok, if you don’t find derived classes to be super important, then it probably isn’t worth hyper-optimizing :-)</div><br class=""><blockquote type="cite" 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="">Instead, the user should have to write:</div><div class=""><br class=""></div><div class="">memberwise&nbsp;init(baseProperty : Int, ...) {</div><div class="">&nbsp; super.init(baseProperty: baseProperty)</div><div class="">}</div></div></div></blockquote><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="">This doesn’t reduce the utility of this feature, and it preserves separability of class from superclass.</div></div></div></blockquote><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Ideally we could avoid writing this manually. &nbsp;We still have an M x N problem (M inherited properties, N subclass initializers). &nbsp;</div><div class=""><br class=""></div><div class="">Writing that manually would’t reduce the utility of the feature in cases where it is applicable, but it does severely limit its applicability to inheritance hierarchies.</div></div></div></blockquote><div><br class=""></div><div>I don’t agree. &nbsp;The ability to manually add parameters to the memberwise initializer, along with the extant requirement to explicitly call super.init seems to directly solve this. &nbsp;This feature is about automating initialization of a single classes properties independent of the superclass. &nbsp;Also, it is very uncommon for a class to expose an initializer for *all* of its properties if it is intended to be subclassed anyway.</div><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="">You’re welcome! &nbsp;I know this proposal is “just” syntactic sugar, but I believe it will have an impact on initialization designs in practice.</div></div></div></blockquote><div><br class=""></div>Yes, I agree, I’m very excited about this for two reasons: 1) I think it is will be highly impactful for all kinds of code written in swift, and 2) it cleans up a half-baked area of the language by replacing it with some thing much better thought out.</div><div><br class=""></div><div><br class=""></div><div>Other comments:</div><div><br class=""></div><div>In "Impact on existing code”, given your proposal, I think that we should keep the implicit memberwise initializer on classes, start generating it for root classes, and generate it for derived classes whose parent has a DI with no arguments (e.g. subclasses of NSObject). &nbsp;We should keep the current behavior where it is generated with internal behavior, and it is surpressed if *any* initializers are defined inside of the type.</div><div><br class=""></div><div>Thanks again for pushing this forward, you can also put me down as the review manager if you’d like.</div><div><br class=""></div><div>-Chris<br class=""></div><br class=""></body></html>