<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 <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> 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 <<a href="mailto:clattner@apple.com" class="">clattner@apple.com</a>> 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 <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> 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. I have updated the proposal to reflect the core functionality and moved everything else to the future enhancements section. 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: <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: <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. I just submitted a PR. I think it’s ready. 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. 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. 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. 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. 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). 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. 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. What is the best way I can help to move this discussion forward in a productive manner? Would it be a good idea to start a new thread on the topic? 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> let x</div><div> let y</div><div><br class=""></div><div> 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. 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. 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. </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. </div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Sounds good. 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. </div><div class=""><br class=""></div><div class="">I really appreciate you noticing that this should really be orthogonal to the base proposal. I’ve already been giving this a lot of thought. It is very clear to me now that a much more general parameter / argument forwarding feature is the right approach. 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). 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. </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. 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. </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. 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. 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. 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. 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. You have to choose between narrower access control or getting the benefit of a memberwise init. 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. 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. 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. 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. 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. 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. There would be no way to prevent synthesis of parameters for more-private members. We have to choose between allowing callers to initialize our internal state or forgoing the benefit of memberwise initialization. </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. 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). 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. You just need to declare a `memberwise init` with explicitly declared parameters for the more-private members and initialize them manually in the body. 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. 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. </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. 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. It’s a privilege to be able to contribute ideas, have them taken seriously and hopefully see them lead to progress in the language. 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"> </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>