<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 11:21 AM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</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=""><div class=""><div class=""><br class=""></div><div class="">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></div></div></div></blockquote><div><br class=""></div><div>Not for me in Xcode 7.2. Has this changed? Maybe it’s my app target? The implicit init() is only visible for me within the same file the struct is defined in.</div><div><br class=""></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=""><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 class=""><br class=""></div><div class="">Would you feel better about the proposal if it did not allow for public memberwise initializers?</div></div></div></div></blockquote><div><br class=""></div><div>Marginally. My main concern is the complexity of the rules, especially when looking at the direction many of the futures take. There are all of these annotations that get put all over that litter the type definition simply to support memberwise inits.</div><div><br class=""></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=""> 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 class=""><br class=""></div><div class="">This is not true. I would still want access control enforced even if memberwise initializers could not be public.</div></div></div></div></blockquote><div><br class=""></div><div>There’s no concern with access control as it’s explicitly handled. I can expose whatever I want as the API and route it however I want in code. </div><div><br class=""></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=""><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 class=""><br class=""></div><div class="">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></div></div></div></blockquote><div><br class=""></div><div>Sure, but your base proposal does not allow a way for there to be more than one memberwise designated initializer. So in the base case, your proposal doesn’t solve what you call the MxN problem. In the futures, you describe ways to annotate inits() so that members aren’t considered in the signature.</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">struct Point {</font></div></div><div><div><font face="Menlo" class=""> let x: Int</font></div></div><div><div><font face="Menlo" class=""> let y: Int</font></div></div><div><div><font face="Menlo" class=""> let z: Int</font></div></div><div><div><font face="Menlo" class=""> </font></div></div><div><div><font face="Menlo" class=""> @nomemberwise(y, z)</font></div></div><div><div><font face="Menlo" class=""> memberwise init(...) {</font></div></div><div><div><font face="Menlo" class=""> y = 0</font></div></div><div><div><font face="Menlo" class=""> z = 0</font></div></div><div><div><font face="Menlo" class=""> }</font></div></div><div><div><font face="Menlo" class=""><br class=""></font></div></div><div><div><font face="Menlo" class=""> @nomemberwise(z)</font></div></div><div><div><font face="Menlo" class=""> memberwise init(...) {</font></div></div><div><div><font face="Menlo" class=""> z = 0</font></div></div><div><div><font face="Menlo" class=""> }</font></div><div><font face="Menlo" class=""><br class=""></font></div><div><div><div><font face="Menlo" class=""> memberwise init(...) {}</font></div></div></div></div><div><div><font face="Menlo" class="">}</font></div></div></blockquote><div><div><br class=""></div><div>Let’s say that for simplicity the @nomemberwise() attribute takes a list of parameters. This is one version of the code that can be written to support zero-ing out by default.</div><div><br class=""></div><div>Or, we can do this (what Swift has today):</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><div><div><font face="Menlo" class="">struct Point {</font></div></div></div></div><div><div><div><div><font face="Menlo" class=""> let x: Int</font></div></div></div></div><div><div><div><div><font face="Menlo" class=""> let y: Int</font></div></div></div></div><div><div><div><div><font face="Menlo" class=""> let z: Int</font></div></div></div></div><div><div><div><div><font face="Menlo" class=""> </font></div></div></div></div><div><div><div><div><span style="font-family: Menlo;" class=""> init(x: Int, y: Int = 0, z: Int = 0) {</span></div><div><span style="font-family: Menlo;" class=""> self.x = x</span></div><div><span style="font-family: Menlo;" class=""> self.y = y</span></div><div><span style="font-family: Menlo;" class=""> self.z = z</span></div></div></div></div><div><div><div><div><span style="font-family: Menlo;" class=""> }</span></div></div></div></div><div><div><div><div><span style="font-family: Menlo;" class="">}</span></div></div></div></div></blockquote><div><div><br class=""></div><div>Or with the below example:</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><div><div><div><div><font face="Menlo" class="">struct Point {</font></div></div></div></div></div></div><div><div><div><div><div><div><font face="Menlo" class=""> let x: Int</font></div></div></div></div></div></div><div><div><div><div><div><div><font face="Menlo" class=""> let y: Int</font></div></div></div></div></div></div><div><div><div><div><div><div><font face="Menlo" class=""> let z: Int</font></div></div></div></div></div></div><div><div><div><div><div><div><font face="Menlo" class=""> </font></div></div></div></div></div></div><div><div><div><div><div><div><span style="font-family: Menlo;" class=""> init(self x: Int, self y: Int = 0, self z: Int = 0) {</span><span style="font-family: Menlo;" class="">}</span></div></div></div></div></div></div><div><div><div><div><div><div><span style="font-family: Menlo;" class="">}</span></div></div></div></div></div></div></blockquote><div><div><br class=""></div><div>Even in all of your futures, I don’t see how you fix the "MxN problem" for let without bringing back the assignment in the type declaration, which was generally not well received.</div><div><br class=""></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 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 class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class="">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></div></div></div></blockquote></div><br class=""><div class="">I think it keeps coming up because it’s far simpler. While there is duplication in the type signature, the code is still smaller, more flexible, and more applicable than being limited to only initialization. Further, and I think this is what is far more important, I only need to look at single place to understand what is going on with initialization for any particular call. I don’t need to find out what members are annotated, or create the list of head of members and exclude certain ones if @nomemberize() is used. Each member being initialized as a configuration entity from the user is right there, no questions asked.</div><div class=""><br class=""></div><div class="">-David</div><div class=""><br class=""></div></body></html>