<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 Jan 8, 2016, at 12:51 PM, David Owens II <<a href="mailto:david@owensd.io" class="">david@owensd.io</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Jan 8, 2016, at 9:31 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 class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" 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;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">Still, I can’t shake unease about the proposed solution. As I read the examples, they’re not quite self-explanatory: a lot of magic, but the result doesn’t feel quite magical. Without being able to see what the compiler synthesizes, it’s often not obvious what will happen. As I read the detailed rules, they all sound quite sensible, but taken together feel like they’ll be hard to keep track of, and will lead to a lot of frustrated experimenting with the compiler. Tricky questions lurk all over. For example, what happens when I have a 7-member struct, all 7 parameters use memberwise initialization, but then I want to add some custom logic for the initialization of member 3? I think I have to either reorder the params or abandon … altogether? I feel like those tricky questions should melt away once I grasp the underlying principle, but there isn’t one to grasp; it’s just a bunch of tricky cases.</div><div class=""><br class=""></div><div class="">On reflection, it comes down to this:<b class=""><span class="Apple-converted-space"> </span>the feature to functionality ratio is too high.</b></div></div></div></blockquote><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="">Would you propose removing the current implicit memberwise initializer for structs on the same grounds? This proposal effectively fleshes that feature out giving it more functionality. The only fundamental complexity it adds is the access control rules, which I feel are pretty important to enforce.</div></div></div></div></blockquote></div><br class=""><div class="">The struct memberwise behavior today is really simple and doesn’t expose a public API allowing for non-exhaustive behavior requirements and a much simpler design.</div><div class=""><br class=""></div><div class="">The struct rule is basically this:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">A member is added to the initializer when the following conditions are true:</div><div class=""> 1. The member is not declared with let and an initialization value</div><div class=""> 2. The member is not a computed property</div><div class=""><br class=""></div><div class="">Also, this generated initializer is only generated when no other init() has been defined.</div></blockquote><div class=""><br class=""></div><div class="">The really important observation though is that it keeps the generated initializer private, which means that there are no real API contracts to consider as it can only be used within your own code. It’s a nicety to have when simply building up some code to solve a problem.</div></div></div></blockquote><div><br class=""></div><div>Actually it is internal, not private, and it exposes private properties via that internal initializer. It’s only in your own code, but I don't think it should be violating access control in that way.</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=""><br class=""></div><div class="">The proposal essentially is doing two things:</div><div class=""><br class=""></div><div class=""> 1. Create a way to generate a public API contract based on a series of fairly complicated rules, potential annotations, and member orderings within the type</div></div></div></blockquote><div><br class=""></div><div>Would you feel better about the proposal if it did not allow for public memberwise initializers?</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=""> 2. Generate the pass through of assignment for the parameters of the init() and their backing values.</div><div class=""><br class=""></div><div class="">The vast amount complexity comes from trying to solve #1.</div></div></div></blockquote><div><br class=""></div><div>This is not true. I would still want access control enforced even if memberwise initializers could not be public.</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=""><br class=""></div><div class="">As for this:</div><div class=""><br class=""></div><div 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=""><div class=""><blockquote type="cite" class="">(Aside, a small nitpick, but it really bugs me: initialization has O(M+N) complexity, not O(M×N) complexity. One doesn’t initialize every member with every parameter.)</blockquote></div></div></div></div></blockquote><blockquote type="cite" class=""><br class=""></blockquote><div class=""><blockquote type="cite" class="">MxN is members x initializers.</blockquote></div></div></div><div class=""><br class=""></div><div class="">Paul, this has also bugged me too; I do not see how it is accurate. There aren’t N initializers, there is one initializer that must fully instantiate the type. Each type may have additional convenience initializers, but these are not required. Further, they cannot make use of the placeholder. There is a “futures” that talks about it, but that’s out of scope of the original proposal. </div></div></div></blockquote><div><br class=""></div><div>Swift allows more than one designated initializer. N never large but it more than 1 in enough cases to matter. The point is that it results in enough boilerplate that I believe it affects how many people design their initializers. </div><blockquote type="cite" 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="">Your example hear illustrates the complexity (slightly modified from your proposal’s usage):</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">struct </font><span style="font-family: Menlo;" class="">Foo {</span></div></div><div class=""><div class=""><span style="font-family: Menlo;" class=""> let</span><span style="font-family: Menlo;" class=""> bar: </span><span style="font-family: Menlo;" class="">String</span></div></div><div class=""><div class=""><span style="font-family: Menlo;" class=""> let</span><span style="font-family: Menlo;" class=""> bas: </span><span style="font-family: Menlo;" class="">Int</span></div></div><div class=""><div class=""><span style="font-family: Menlo;" class=""> let</span><span style="font-family: Menlo;" class=""> baz: </span><span style="font-family: Menlo;" class="">Double</span></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class=""> init(self bar: String, self bas: Int, bax: Int</font><span style="font-family: Menlo;" class="">) {</span></div></div><div class=""><div class=""><span style="font-family: Menlo;" class=""> // self.bar = bar synthesized by the compiler</span></div></div><div class=""><div class=""><div class=""><span style="font-family: Menlo;" class=""> // self.bas = bas synthesized by the compiler</span></div></div></div><div class=""><div class=""><div class=""><span style="font-family: Menlo;" class=""> self</span><span style="font-family: Menlo;" class="">.</span><span style="font-family: Menlo;" class="">baz </span><span style="font-family: Menlo;" class="">=</span><span style="font-family: Menlo;" class=""> </span><span style="font-family: Menlo;" class="">Double</span><span style="font-family: Menlo;" class="">(bax)</span></div></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote></div></blockquote><div><br class=""></div><div>This approach has been mentioned quite a few times. It results in a lot of duplication without saving a lot. This is especially true if you have a lot of properties and more than one designated initializer that could use memberwise initialization . </div><div><br class=""></div><div>IMO, if we were going to take this approach we should at least be able to omit redundant type information and default values for `var` properties where they exist. At least then we are saving as much as we can under this approach.</div><div><br class=""></div><div>struct Foo {<br class=""> let bar: String<br class=""> let bas: Int<br class=""> let baz: Double<br class=""><br class=""> init(self bar, self bas, bax: Int) {<br class=""> // self.bar = bar synthesized by the compiler<br class=""> // self.bas = bas synthesized by the compiler<br class=""> self.baz = Double(bax)<br class=""> }<br class="">}</div><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></blockquote><div class="">The only thing I see your proposal removing is the re-typing of all of the members in the init signature that can be configured. And in fact, the current proposal doesn't support this. You have a futures section that looks a way to make this possible kinda like this:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><font face="Menlo" class="">struct </font><span style="font-family: Menlo;" class="">Foo {</span></div><div class=""><span style="font-family: Menlo;" class=""> let</span><span style="font-family: Menlo;" class=""> bar: </span><span style="font-family: Menlo;" class="">String</span></div><div class=""><div class=""><span style="font-family: Menlo;" class=""> let</span><span style="font-family: Menlo;" class=""> bas: </span><span style="font-family: Menlo;" class="">Int</span></div></div><div class=""><div class=""><span style="font-family: Menlo;" class=""> let</span><span style="font-family: Menlo;" class=""> baz: </span><span style="font-family: Menlo;" class="">Double</span></div></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class=""> @nomemberwize(baz)</font></div><div class=""><font face="Menlo" class=""> memberwise init(..., bax: Int</font><span style="font-family: Menlo;" class="">) {</span></div><div class=""><div class=""><span style="font-family: Menlo;" class=""> // self.bar = bar synthesized by the compiler</span></div></div><div class=""><div class=""><span style="font-family: Menlo;" class=""> // self.bas = bas synthesized by the compiler</span></div><div class=""><span style="font-family: Menlo;" class=""> self</span><span style="font-family: Menlo;" class="">.</span><span style="font-family: Menlo;" class="">baz </span><span style="font-family: Menlo;" class="">=</span><span style="font-family: Menlo;" class=""> </span><span style="font-family: Menlo;" class="">Double</span><span style="font-family: Menlo;" class="">(bax)</span></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote><div class=""><div class=""><br class=""></div></div></div></blockquote><div><br class=""></div></div></body></html>