<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 Dec 27, 2015, at 9:51 AM, Matthew Johnson 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 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=""><br class="Apple-interchange-newline">On Dec 26, 2015, at 11:31 PM, Chris Lattner &lt;<a href="mailto:clattner@apple.com" class="">clattner@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;">On Dec 25, 2015, at 12:04 PM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>&gt; wrote:<br class=""><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=""><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=""><div class="">Discussion on a couple of topics continues inline below as well.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Great, comments below:</div></div></div></div></blockquote><div class=""><br class=""></div>Thanks for continuing the discussion. &nbsp;I have updated the proposal to reflect the core functionality and moved everything else to the future enhancements section. &nbsp;I think this draft is ready or nearly ready for a PR.</div><div class=""><br class=""></div><div class="">Here is a link to the current draft:&nbsp;<a href="https://github.com/anandabits/swift-evolution/edit/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md" class="">https://github.com/anandabits/swift-evolution/edit/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md</a></div><div class=""><br class=""></div><div class="">Here is a link to the commit diff:&nbsp;<a href="https://github.com/anandabits/swift-evolution/commit/f15360d2e201709640f9137d86a8b705a07b5466?short_path=f5ec377#diff-f5ec377f4782587684c5732547456b70" class="">https://github.com/anandabits/swift-evolution/commit/f15360d2e201709640f9137d86a8b705a07b5466?short_path=f5ec377#diff-f5ec377f4782587684c5732547456b70</a></div></div></div></blockquote><div class=""><br class=""></div><div class="">Thanks again for pushing this forward, this is looking great.</div></div></div></div></blockquote><div class=""><br class=""></div>Sounds good. &nbsp;I just submitted a PR. &nbsp;I think it’s ready. &nbsp;Please let me know if you feel any further changes are necessary.</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=""><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><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=""><div class="">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></div></div></blockquote><div class=""><br class=""></div><div class="">I agree with this. &nbsp;I can accept an argument that this provides enough value to avoid changing the language.</div><div class=""><br class=""></div><div class="">That said, I do think default values for let properties are higher value. &nbsp;If I had to pick one it would be default values and I would consider it to be worthy of a breaking change in the language. &nbsp;But It would be great if we can find a way to support both.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">I understand your desire, but this really is something we’ll have to discuss carefully. &nbsp;Changing Swift soft that “let x = 42” doesn’t necessarily mean that x is 42 is a pretty deep semantic change, which will be surprising for many people (as was noted by others on this thread). &nbsp;I agree that it would be great to get more flexible initialization for lets, but keep in mind that you can already do this long-hand if you want.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">I know changing the existing behavior would require very careful thinking. &nbsp;I am absolutely open to any solution that allow a default value for let properties to be specified whether it changes the existing behavior or not. &nbsp;What is the best way I can help to move this discussion forward in a productive manner? &nbsp;Would it be a good idea to start a new thread on the topic? &nbsp;Or is this something you feel like the core team needs to mull over for a while before we can have a productive conversation on the list?</div></div></div></blockquote><div><br class=""></div><div>At least for structs, there's almost no reason for the memberwise-initialized properties to be `let`s, since preventing partial mutation of a value doesn't put any effective limits on users of the type. If you have:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div>struct Foo {</div><div>&nbsp; let x</div><div>&nbsp; let y</div><div><br class=""></div><div>&nbsp; memberwise init(...)</div><div>}</div><div><br class=""></div></div></blockquote>then even though you can't say:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">var foo = Foo(x: 1, y: 1)</div><div class="">foo.x = 2</div><div class=""><br class=""></div></blockquote>you can do the equivalent partial update by memberwise initialization:<div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">var foo = Foo(x: 1, y: 1)</div><div class="">foo = Foo(x: 2, y: foo.y)</div><div class=""><br class=""></div></blockquote>and it's highly likely both forms will be optimized to the same thing.<div class=""><br class=""></div><div class="">-Joe<br class=""><div class=""><div class=""><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=""><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><blockquote type="cite" 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="">This I still have a concern with, in two ways:<br class=""><div class=""><br class=""></div><div class="">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></div></div></blockquote><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="">2) You’re introducing another unnecessary feature "super.init(…)” which will have to be independently justified.&nbsp;</div><div class=""><br class=""></div></div></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">I will continue thinking about how this might be solved and also about other cases where such a forwarding feature might be useful. &nbsp;</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Sounds good. &nbsp;This is definitely an interesting area to investigate, but I don't want the general goodness of your base memberwise init proposal to have to wait :-)</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">I agree with you on not holding back the base proposal. &nbsp;</div><div class=""><br class=""></div><div class="">I really appreciate you noticing that this should really be orthogonal to the base proposal. &nbsp;I’ve already been giving this a lot of thought. &nbsp;It is very clear to me now that a much more general parameter / argument forwarding feature is the right approach. &nbsp;I am going to pursue a proposal for that as well.</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><blockquote type="cite" 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="">Other comments:</div><div class=""><br class=""></div><div class="">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></div></blockquote><div class=""><br class=""></div><div class="">I’ll update that section to reflect these comments. &nbsp;</div><div class=""><br class=""></div><div class="">One question I have is what the implicit memberwise initializer should do in the case of private members. &nbsp;If we make it follow the rules of this proposal we would break existing structs with private members that are currently receiving the implicit memberwise initializer. &nbsp;</div><div class=""><br class=""></div><div class="">I think this would be a good breaking change for both consistency with this proposal and because implicitly exposing private members via the initializer was a questionable choice. &nbsp;A mechanical migration could generate code to add an explicit implementation of the previously implicit initializer that doesn’t qualify under the rules of the new proposal. &nbsp;How do you feel about this?</div></div></div></blockquote><div class=""><br class=""></div><div class="">I don’t have a strong opinion about this, and I can see reasonable arguments on either side. &nbsp;Breaking source compatibility in this case isn’t a show-stopper, since this will roll out in Swift 3.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Glad to hear breaking compatibility is ok in this case if it is required for consistency.</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="">Here are the pros and cons as I see them with disallow-ing more-private fields to be published through less-private memberwise inits:</div><div class=""><br class=""></div><div class="">Neutral: Either approach is fine for “CGRect” like types that are really just public bags of public fields.</div><div class="">Pro: Makes logical sense at first blush. &nbsp;Memberwise inits publishing private state would be odd/surprising.</div><div class="">Pro: Safer default, in that you don’t accidentally publish stuff you don’t want through a memberwise init.</div><div class="">Con: This puts tension between access control for stored properties and memberwise inits. &nbsp;You have to choose between narrower access control or getting the benefit of a memberwise init. &nbsp;Another way to say it: this design means that narrow access control leads to boilerplate.</div><div class=""><br class=""></div><div class="">I’m sure there are others as well.</div><div class=""><br class=""></div><div class="">Again, I don’t have a strong opinion, but I’d lean slightly towards publishing all stored properties through the memberwise init. &nbsp;If you don’t have a strong opinion either, it would be fine to add a section pointing out the tradeoffs, and we can all discuss it during the review period. &nbsp;I suspect some of the other core team folks will have an opinion on this as well.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">I briefly addressed this in the alternatives considered section. &nbsp;I’ll fill that out with additional details including the points you raise.</div><div class=""><br class=""></div><div class="">I feel pretty strongly that we should enforce the access control rules stated in the proposal. &nbsp;In addition to the Pros you note:</div><div class=""><br class=""></div><div class="">1. I think it is usually the right thing to do. &nbsp;If the caller can’t see a member it probably doesn’t make sense to allow them to initialize it.</div><div class=""><br class=""></div><div class="">2. If we expose more private-members by default then memberwise initialization is useless under the current proposal in many cases. &nbsp;There would be no way to prevent synthesis of parameters for more-private members. &nbsp;We have to choose between allowing callers to initialize our internal state or forgoing the benefit of memberwise initialization.&nbsp;</div><div class=""><br class=""></div><div class="">3. If a proposal for `@nomemberwise` is put forward and adopted that would allow us to prevent synthesis of parameters for members as desired. &nbsp;Unfortunately `@nomemberwise` would need to be used much more heavily than it otherwise would (i.e. to prevent synthesis of memberwise parameters for more-private members). &nbsp;It would be better if `@nomemberwise` was not necessary most of the time.</div><div class=""><br class=""></div><div class="">4. If callers must be able to provide memberwise arguments for more-private members directly it is still possible to allow that while taking advantage of memberwise initialization for same-or-less-private members. &nbsp;You just need to declare a `memberwise init` with explicitly declared parameters for the more-private members and initialize them manually in the body. &nbsp;Requiring the programmer to manually write any code that exposes more-private members is a arguably a very good thing.</div><div class=""><br class=""></div><div class="">I think #4 above addresses the con you mention pretty well and #2 above is a significant drawback to not enforcing the access control rule (#3 is also pretty significant IMO).</div><div class=""><br class=""></div><div class="">I’m sure this will be a point of discussion during review. &nbsp;I’m prepared to defend the decision I made but will also keep my mind open to opposing arguments.</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="">I sent you a PR (my first! :-) with some nit-picky details on the latest writeup, to fix typos, clarify a few things, and reduce redundancy. &nbsp;</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Thanks!</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="">One point that I left:</div><div class=""><div class=""><br class=""></div><div class=""></div><blockquote type="cite" class=""><div class="">The *implicitly* synthesized initializer will be identical to an initializer declared *explicitly* as follows:</div><div class=""><br class=""></div><div class="">1. For structs and root classes: `memberwise init(...) {}`</div><div class="">2. For derived classes: `memberwise init(...) { super.init() }`</div></blockquote><div class=""><br class=""></div><div class="">Note that these are both equivalent, since derived class initializers default to super.init() at the bottom of their body today. &nbsp;This is why you don’t have to call super.init() when deriving from NSObject, for example.</div></div></div></div></div></blockquote><div class=""><br class=""></div>I’ll add a note to make this clear.</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=""><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=""><div class=""><br class=""></div></div><br class=""><blockquote type="cite" 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="">Thanks again for pushing this forward, you can also put me down as the review manager if you’d like.</div><div class=""></div><div class=""><br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">You’re very welcome. &nbsp;It’s a privilege to be able to contribute ideas, have them taken seriously and hopefully see them lead to progress in the language. &nbsp;I’ve really enjoyed the process and discussions with the core team as well as the broader community.</div><div class=""><br class=""></div><div class="">It’s really incredible to see the Swift team embrace the community so openly and so graciously!</div><div class=""><br class=""></div><div class="">Merry Christmas!</div></div></div></blockquote><br class=""></div><div class="">You too Matthew, thanks again,</div><div class=""><br class=""></div><div class="">-Chris</div><br class=""></div></div></blockquote></div><br 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;"><img src="https://u2002410.ct.sendgrid.net/wf/open?upn=RoDF4MveSEMYBIqIJA6ub1g8cOZ-2BVYvqV-2FqygPhjPn-2F0-2FfWu-2B9DoyT2LqAMrvuoeKaIlIZCZaU4qMg8v3fXcLHox05p-2Fcq2yxf4ZuSYcrgWcI8H0vE03R1VMBOuWgQ5ffU3nN8IniBq5y3xIo42ON7m2mkqsqIbsT9lE7minn667-2BQSjf11BdGov7vHMtyVEblZcwk-2BINh8yxr3M-2FWsVro7ug6LbG8BilqDn93xTVdE-3D" alt="" width="1" height="1" border="0" 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; height: 1px !important; width: 1px !important; border-width: 0px !important; margin: 0px !important; padding: 0px !important;" class=""><span 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; float: none; display: inline !important;" class=""><span class="Apple-converted-space">&nbsp;</span></span><span 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; float: none; display: inline !important;" class="">_______________________________________________</span><br 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=""><span 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; float: none; display: inline !important;" class="">swift-evolution mailing list</span><br 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=""><a href="mailto:swift-evolution@swift.org" 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="">swift-evolution@swift.org</a><br 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=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" 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="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div><br class=""></div></div></div></body></html>