[swift-evolution] [Review] SE-0018 Flexible Memberwise Initialization

Matthew Johnson matthew at anandabits.com
Thu Jan 7 20:57:51 CST 2016


> On Jan 7, 2016, at 8:30 PM, Joe Groff <jgroff at apple.com> wrote:
> 
>> 
>> On Jan 7, 2016, at 11:30 AM, Matthew Johnson <matthew at anandabits.com <mailto:matthew at anandabits.com>> wrote:
>> 
>> 
>>> On Jan 7, 2016, at 12:51 PM, Joe Groff <jgroff at apple.com <mailto:jgroff at apple.com>> wrote:
>>> 
>>> 
>>>> On Jan 7, 2016, at 10:49 AM, Matthew Johnson <matthew at anandabits.com <mailto:matthew at anandabits.com>> wrote:
>>>> 
>>>>> 
>>>>> On Jan 7, 2016, at 12:37 PM, Joe Groff <jgroff at apple.com <mailto:jgroff at apple.com>> wrote:
>>>>> 
>>>>> 
>>>>>> On Jan 7, 2016, at 10:32 AM, David Owens II <david at owensd.io <mailto:david at owensd.io>> wrote:
>>>>>> 
>>>>>> And this is more clear than this?
>>>>>> 
>>>>>> class Foo {
>>>>>>   var x,y,z: Int
>>>>>>   init(x: Int, y: Int, z: Int) {
>>>>>>     self.x = x
>>>>>>     self.y = y
>>>>>>     self.z = z
>>>>>>   }
>>>>>> }
>>>>> 
>>>>> No, it isn't, but Matthew asked… I'm personally not too motivated to support anything more than all-or-nothing memberwise initialization, and tend to agree that anything more specialized deserves an explicit implementation.
>>>> 
>>>> Maybe you would feel differently if you were an app developer.  Different kinds of code have different needs.  The most important use cases I have in mind are related to UI code, which is often the majority of the code in an app.
>>> 
>>> Do you have any concrete examples in mind?
>>> 
>>> -Joe
>>> 
>> 
>> Here is an example where partial memberwise initialization would apply.  It is similar to something in a real project:
>> 
>> public class FontPicker: UIControl {
>>   public let fonts: [UIFont]
>> 
>>   public var fontSize: CGFloat = 22
>>   public var foregroundColor: UIColor = UIColor.darkGrayColor()
>>   public var backgroundColor: UIColor = UIColor.whiteColor()
>>   // A bunch of other appearance attributes here
>> 
>>   private let collectionView: UICollectionView
>>   private let layout: UICollectionViewLayout
>>   // other internal state required by the implementation
>> 
>>   public memberwise init(...) {
>>     // configure the collection view and add it as a subview
>>   }
>> }
>> 
>> A couple points are relevant here:
>> 
>> 1. Memberwise initialization is very valuable for the appearance attributes, but is useless if it exposes our implementation details.
>> 
>> 2. In many custom UI widgets the appearance attributes don’t really need to be mutable post-initialization.  At the same time, it is necessary to allow, but not require a value to be specified.  It would be ideal if they were `let` properties with a default value, but still able to participate in memberwise initialization.  Without that capability we are forced to choose between the advantages of using a `let` property and the advantages of memberwise initialization.
>> 
>> UI widgets are a great example.  View controllers often have a similar divide between state provided by the user and state related to internal implementation details.
> 
> Access control seems like a poor tool for the kind of categorization you want here. The vast majority of code is app code, where there's no reason to use 'public', so 'internal' and 'private' are the interesting visibility layers. Using 'private' to opt fields out of memberwise initialization is too brittle, in my opinion—You've made it much harder to factor the class's functionality into different files in the future, since you can no longer change any of these fields to internal without also breaking all of the memberwise initializers as a second-order effect.

That is a reasonable position.  In practice it wouldn’t be a problem for projects I’ve worked on, and I suspect others would say the same or may have commented on this already.  But I do understand why you want to avoid the possibility of increasing the visibility of a member breaking code.  

Nevertheless, I feel that access control rules should be applied to memberwise initializers unless we go with the opt-in model where the programmer explicitly states which properties are relevant to memberwise initialization and which are not.  I don’t think exposing more-private members in an more-public initializers without an explicit request to do so is a good idea.  And I don’t think the `memberwise` declaration modifier on the initializer itself is enough to constitute and explicit request to do this.

The safest, most clear, most robust way to determine the correct set of properties to use is to go with the opt-in model.  The downside of that is that it requires a declaration modifier on properties to opt-in.  I am not opposed to going down this path at all, but I believe Chris thinks it would be too verbose for a convenience feature to require that (although he seemed to be comfortable with offering it as an alternative when requested in a specific case by the programmer).

Matthew

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160107/49f77541/attachment.html>


More information about the swift-evolution mailing list