> On Dec 28, 2015, at 12:59 PM, Joe Groff <jgr...@apple.com> wrote: > >> >> On Dec 27, 2015, at 9:51 AM, Matthew Johnson via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >> >>> >>> On Dec 26, 2015, at 11:31 PM, Chris Lattner <clatt...@apple.com >>> <mailto:clatt...@apple.com>> wrote: >>> >>> On Dec 25, 2015, at 12:04 PM, Matthew Johnson <matt...@anandabits.com >>> <mailto:matt...@anandabits.com>> wrote: >>>>>> Discussion on a couple of topics continues inline below as well. >>>>> >>>>> Great, comments below: >>>> >>>> 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. >>>> >>>> Here is a link to the current draft: >>>> https://github.com/anandabits/swift-evolution/edit/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md >>>> >>>> <https://github.com/anandabits/swift-evolution/edit/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md> >>>> >>>> Here is a link to the commit diff: >>>> https://github.com/anandabits/swift-evolution/commit/f15360d2e201709640f9137d86a8b705a07b5466?short_path=f5ec377#diff-f5ec377f4782587684c5732547456b70 >>>> >>>> <https://github.com/anandabits/swift-evolution/commit/f15360d2e201709640f9137d86a8b705a07b5466?short_path=f5ec377#diff-f5ec377f4782587684c5732547456b70> >>> Thanks again for pushing this forward, this is looking great. >> >> Sounds good. I just submitted a PR. I think it’s ready. Please let me >> know if you feel any further changes are necessary. >> >>> >>>>> It is also annoying that writing it as a static property would force you >>>>> to write something like “X.a" instead of just “a”. >>>> >>>> I agree with this. I can accept an argument that this provides enough >>>> value to avoid changing the language. >>>> >>>> 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. >>> >>> 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. >> >> 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? > > 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: > > struct Foo { > let x > let y > > memberwise init(...) > } > > then even though you can't say: > > var foo = Foo(x: 1, y: 1) > foo.x = 2 > > you can do the equivalent partial update by memberwise initialization: > > var foo = Foo(x: 1, y: 1) > foo = Foo(x: 2, y: foo.y) > > and it's highly likely both forms will be optimized to the same thing.
Yes, understood. The use cases for `let` with a default I have in mind are classes. For example, UI widgets with some internal state but also appearance properties. In my experience it is often not a requirement and worth the added complexity to allow mutation of appearance attributes in custom UI widgets, but they always have a default value that is often, but not always used. There are definitely workarounds, but a `let` with a default value feels like the most natural solution. I hope we can continue discussing how it might be possible to support this (whether by adding a feature or changing existing behavior). > > -Joe > >> >>> >>>>> This I still have a concern with, in two ways: >>>>> >>>>> 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. >>>>> >>>>> 2) You’re introducing another unnecessary feature "super.init(…)” which >>>>> will have to be independently justified. >>>>> >>>> >>>> I will continue thinking about how this might be solved and also about >>>> other cases where such a forwarding feature might be useful. >>> >>> 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 :-) >> >> I agree with you on not holding back the base proposal. >> >> 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. >> >>> >>>>> Other comments: >>>>> >>>>> 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. >>>> >>>> I’ll update that section to reflect these comments. >>>> >>>> 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. >>>> >>>> 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? >>> >>> 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. >> >> Glad to hear breaking compatibility is ok in this case if it is required for >> consistency. >> >>> >>> Here are the pros and cons as I see them with disallow-ing more-private >>> fields to be published through less-private memberwise inits: >>> >>> Neutral: Either approach is fine for “CGRect” like types that are really >>> just public bags of public fields. >>> Pro: Makes logical sense at first blush. Memberwise inits publishing >>> private state would be odd/surprising. >>> Pro: Safer default, in that you don’t accidentally publish stuff you don’t >>> want through a memberwise init. >>> 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. >>> >>> I’m sure there are others as well. >>> >>> 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. >> >> I briefly addressed this in the alternatives considered section. I’ll fill >> that out with additional details including the points you raise. >> >> I feel pretty strongly that we should enforce the access control rules >> stated in the proposal. In addition to the Pros you note: >> >> 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. >> >> 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. >> >> 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. >> >> 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. >> >> 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). >> >> 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. >> >>> >>> 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. >> >> Thanks! >> >>> One point that I left: >>> >>>> The *implicitly* synthesized initializer will be identical to an >>>> initializer declared *explicitly* as follows: >>>> >>>> 1. For structs and root classes: `memberwise init(...) {}` >>>> 2. For derived classes: `memberwise init(...) { super.init() }` >>> >>> 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. >> >> I’ll add a note to make this clear. >> >>> >>> >>>>> Thanks again for pushing this forward, you can also put me down as the >>>>> review manager if you’d like. >>>>> >>>> >>>> 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. >>>> >>>> It’s really incredible to see the Swift team embrace the community so >>>> openly and so graciously! >>>> >>>> Merry Christmas! >>> >>> You too Matthew, thanks again, >>> >>> -Chris >>> >> >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution