> 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

Reply via email to