[Review] SE-0018 Flexible Memberwise Initialization

After reading both your response below and also the proposal rather carefully, I agree that the possible issues I raised are all either not real issues or already addressed; thanks again for crafting the proposal and also for taking the time to reply to so much feedback.

That being said, I can’t shake a feeling that, overall, although I am definitely in favor of something along the lines of this proposal, in its concrete details at present this proposal isn’t really sitting anywhere near even a local-optimum on the `(flexibility,complexity) -> functionality` surface, as it were; it seems like both of these are possible:

- (a) make it a bit more flexible, for a high gain in functionality at a low incremental cost in complexity
- (b) make it a bit less flexible, for a modest loss in functionality and a large drop in complexity

…but for (b) it’s just a feeling and I don’t have a specific proposal (this may well be close to a minimum-viable-proposal for such a feature).

I agree with you.

As for (b) some people have suggested alternatives with less functionality like David’s `self propName: PropType` suggestion. So far I don’t think any of those add enough value over current state to be worth considering.

For (a) my sense is that although I can understand why you don’t want to even provide the option of specifying an explicit memberwise-parameter list, it really does seem that supporting at least an optional list makes it possible to get a lot more functionality for not much more *actual* complexity; this isn’t incompatible with also supporting an “automatic” option that uses the logic from the proposal where possible.

In terms of (a), I definitely agree that it would be desirable to allow for a bit more functionality. That is why I have suggested several enhancements. I don’t think we want all of them, but some are definitely desirable.

Chris really wanted to start with a core proposal and evaluate the enhancements independently, which is a good idea but also makes the proposal slightly less flexible than desirable. The enhancements I feel are most important are:

1. We need a way to specify a default value for memberwise parameters for `let` properties.
2. We need a little bit more control over which properties participate in memberwise initialization when the “automatic” rules don’t quite do the right thing for a particular use case. I think allowing distinct access control for `init` is the best way to handle this.

You mention specifying an explicit parameter list but don’t really elaborate further. Would the opt-in model described in the proposal meet what you have in mind? Or are you also consider with parameter order being independent of property declaration order?

I included a mock syntax in my initial response but it was (a) at the end and (b) perhaps a bit too terse. I have put a restated sketch at the bottom of this response.

Your example below hints at general parameter forwarding. I’ll elaborate further down.

Here’s a concrete example to illustrate why I’m harping on this point; I apologize for the length, but I think “small-n” examples can often give false intuition into how things will behave in real life:

Thank you for this! I probably should have provided at least one more concrete example myself. I am learning from that mistake in the second draft of my next proposal.

class FancyCollectionViewDriver : NSObject, UICollectionViewDataSource, UICollectionViewDelegate /*, etc... */ {
  
  let collectionView: UICollectionView
  let contentPresentation: ContentPresentation
  let modelBroker: ModelBroker
  let imageBroker: ImageBroker
  let analyticsSink: AnalyticsSink
  private(set) var currentData: ModelData
  private(set) weak var interactionDelegate: DriverDelegateProtocol?
  // ^ can't be non-optional `unowned let` for reasons,
  // but we expect a non-nil argument in init
  // NOTE: numerous private state-tracking variables omitted since we are only focusing on initialization

  // Present-day initializer, full of boilerplate:
  required init(
    collectionView: UICollectionView,
    contentPresentation: ContentPresentation,
    modelBroker: ModelBroker,
    imageBroker: ImageBroker,
    analyticsSink: AnalyticsSink,
    // note use of different argument name:
    initialData: ModelData,
    // note use of non-optional:
    interactionDelegate: DriverDelegateProtocol) {
      // oh boy here we go again:
      self.collectionView = collectionView
      self.contentPresentation = contentPresentation
      self.modelBroker = modelBroker
      self.imageBroker = imageBroker
      self.analyticsSink = analyticsSink
      self.currentData = initialData
      self.interactionDelegate = interactionDelegate
      super.init()
      // only non-assignment logic in the entire init:
      self.collectionView.dataSource = self
      self.collectionView.delegate = self
    }
    
    // best we can do under proposal w/out modifying
    // class design:
    required memberwise init(
    // lots of boilerplate gone:
    ...,
    // this isn't changed:
    initialData: ModelData,
    // this isn't changed:
    interactionDelegate: DriverDelegateProtocol) {
      // synthesized stuff is effectively here
      self.currentData = initialData
      self.interactionDelegate = interactionDelegate
      super.init()
      // only non-assignment logic in the entire init:
      self.collectionView.dataSource = self
      self.collectionView.delegate = self
    }
  
}

…which I do think is already a huge improvement.

And gets even better if we allow access control for init. Your `private(set)` members would now become eligible for memberwise initialization in an `internal` initializer because `init` has a distinct access level which defaults to `internal`.

Indeed, but please do note that I’d still like:
- `initialData` instead of `currentData`
- a non-nil `interactionDelegate` at init

That said, I feel that e.g. for any variable declaration syntax something like `private(set) internal(init=initialData) var currentData: ModelData` would be best avoided, even if it’d buy me the ability to customize the name in the synthesized memberwise init; it’s just too much and IMHO sets a bad precedent.

    required memberwise init(...) {
      // synthesized stuff is effectively here
      super.init()
      // only non-assignment logic in the entire init:
      self.collectionView.dataSource = self
      self.collectionView.delegate = self
    }

Now suppose that stored-properties-in-extensions hits (as the "partial-init" flavor); in that case I’d ideally be able to move some of the parts into their own files like so:

// in `FancyCollectionViewDriver+Analytics.swift`
extension FancyCollectionViewDriver {
  // ^ depending on advances in the protocol system, at some point may
  // evolve into a protocol-adoption to get useful default implementations
  
  let analyticsReporter: AnalyticsReporter
  // ^ moved here, not in main declaration
  // assume also a bunch of private state-tracking stuff...
  
  // a bunch of things like this:
  func reportEventTypeA(eventAInfo: EventAInfo)
  func reportEventTypeB(eventBInfo: BventAInfo)
  
}

// in `FancyCollectionViewDriver+Interaction.swift`
extension FancyCollectionViewDriver {
  
  private(set) var interactionDelegate: DriverDelegateProtocol?
  // ^ moved here, not in main declaration
  // assume also a bunch of private state-tracking stuff...
  
  // a bunch of things like this:
  func handleInteractionA(interactionAInfo: InteractionAInfo)
  func handleInteractionB(interactionBInfo: InteractionBInfo)
  
}

…(and so on for e.g. the `imageBroker` also), but under the current proposal this would put them outside the scope of a memberwise init (this isn’t news to you, I’m just making it concrete).

So in this scenario, we’re either reapproaching the MxN problem memberwise-init is meant to avoid:

init(
  // still save some boilerplate:
  …,
  imageBroker: ImageBroker,
  analyticsReporter: AnalyticsReporter,
  initialData: ModelData,
  interactionDelegate: DriverDelegateProtocol) {
  // some boilerplate synththesized here...
  // ...but getting closer to where we started:
  self.partial_init(imageBroker: imageBroker)
  self.partial_init(analyticsReporter: analyticsReporter)
  self.currentData = modelData
  self.partial_init(interactionDelegate: interactionDelegate)
  super.init()
  self.collectionView.dataSource = self
  self.collectionView.delegate = self
}

…or we’re making choices between taking full-advantage of properties-in-extensions (which IMHO would often be a *huge* readability win) versus taking full-advantage of boilerplate-reduction in our inits.

If extensions with stored properties are going to properly encapsulate their state (I believe this is the way to go) they are going to have to initialize state on their own and the primary initializer will have to provide arguments the initializer requires. Allowing stored properties in extensions automatically appear in a memberwise initializer violates that encapsulation.

"Automatic appearance" would definitely be bad; it’d seem like using such extensions would have to get you disqualified for automatic synthesis.

It’s still a tricky point though given the uncertainty about future directions; there seems to be some discussion of allowing protocols to define (instead of merely require) stored properties, which would perhaps be yet-another wrinkle to have to at least consider.

The good news is that a general parameter forwarding mechanism can help if the extension init (or super init) requires a bunch of arguments and you just want to forward them from your caller. This is alluded to in the enhancement section of the proposal but is really a completely general and orthogonal feature.

It might look something like this:

memberwise init(…superArgs, …partial1args, …partial2args, …memberwise) {
  extension1.init(directArgument: 42, …partial1args)
  extension2.init(…partial2args)
  super.init(…superArgs)
}

A couple things to note about how this might work:

1. The initializer calls (or function / method calls in other cases) must be unambiguous from the code alone.
2. Any parameters for which a direct argument is not provided are “captured” by the `…identifier` placeholder.
3. Parameters matching those captured by the identifier are synthesized in the location specified in the parameter list.

Obviously this won’t help if the extensions only require a single argument. But if you have extensions requiring several arguments that you want to pass through it would help

Which is ultimately why I suspect that the “right" version of the proposed feature should cut to the chase and incorporate some way to explicitly-specify the memberwise parameter list — which, again, need not be incompatible with the ability to request automatic synthesis using logic ~ what’s in the proposal — as such an explicit list takes the pressure off of getting the default behavior as-right-as-possible while also making it simpler to support some very nice-to-have capabilities not supported by this proposal as-written.

How would this be different than the opt-in model described in the proposal? Do you have something specific in mind?

This is what I had in the original. To expand what I meant a bit:

- you’d a type into “memberwise" by including `@memberwise` somewhere in the declaration
- `@memberwise` can be used two ways:
  - “bare" `@memberwise` => try to use the automatic approach (~ the logic in this proposal, or similar)
  - `@memberwise($parameterList)`, for explicit lists

…with some examples for the $parameterList in a second.

Assume a class like so:

class Example {
  let foo: Foo
  var bar: Bar = Bar.standard
  var baz: Baz = Baz.standard
}

Then here are some @memberwise declarations:

@memberwise => init(foo: Foo, bar: Bar = Bar.standard, baz: Baz = Baz.standard)
// ^ automatic, roughly ~ proposal

@memberwise(foo,bar,baz) => same as above
// ^ explicit, but identical

@memberwise(foo,baz,bar) => init(foo: Foo, baz: Baz = Baz.standard, bar: Bar = Bar.standard)
// ^ explicit, but reordered arguments

@memberwise(foo,bar=Foo.funkyAlternative,baz) => init(foo: Foo, bar: Bar = Bar.funkyAlternative, baz: Baz = Baz.standard)
// ^ explicit, alternate default for `bar`

@memberwise(foo,bar=,baz) => init(foo: Foo, bar: Bar, baz: Baz = Baz.standard)
// ^ explicit, suppress default for `bar`
// …”suppression" syntax isn’t great but it would seemingly work...

@memberwise(foo=Foo.common,bar,baz) => init(foo: Foo = Foo.common, bar: Bar = Bar.standard, baz: Baz = Baz.standard)
// ^ explicit, provide default for the `let`-property `foo`

…and perhaps even the ugly-but-serviceable renaming support like:

@memberwise(foo,bar,baz as initialBaz=) => init(foo: Foo, bar: Bar = Bar.standard, initialBaz: Baz)

…but not sure how to have a non-awful syntax for the case where you want to “promote” a property that’s internally optional to the non-optional case (or vice-versa I guess, or some more-general not-the-same type; that may be out-of-scope).

Note that something like the above would also offer a natural way to handle superclass initialization:

@memberwise(…,$parameterList) => this type’s parameters come *after* parent classes’ (memberwise) parameters
@memberwise($parameterList, ..) => this type’s parameters come *before* parent classes’ (memberwise) parameters

…although I’m not sure how often that’d come up in practice.

This is not a concrete proposal; it’s just a sketch of how an explicit parameter-list could be designed to still support the automatic approach when possible. I’m assuming that it’s a compiler error to have an explicit list that is either (a) incomplete or (b) has any invalid/unrecognized property names.

It also feels weird to have an @-style annotation *inside* a type, so there’s a lot of room to improve the proposed syntax.

And all the other arguments against the explicit list would also still apply, of course.

···

On Jan 8, 2016, at 11:56 AM, Matthew Johnson <matthew@anandabits.com> wrote:

On Jan 8, 2016, at 9:46 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

That’s my 2c; thanks to anyone who’s read through all this and thanks again for drafting a concrete-enough proposal to discuss properly.

Thanks for all your feedback and your example! I really appreciate it!

Matthew

On Jan 7, 2016, at 9:24 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On Jan 7, 2016, at 9:02 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the general notion of something along these lines but admittedly haven’t had time to dig into the proposal specifics yet.

I have some concerns about cross-interactions with other features that are either also under discussion or are at least very anticipatable.

First, I know there has already been some discussion of allowing definition of stored fields in (some) extensions (e.g., something like allowing definition of stored fields in extensions within the module that defines the type).

E.G., something like this may become possible (assume all files are compiled together):

  // in `ComplicatedClass.swift`
  class ComplicatedClass {
    let text: String

    // how will this get expanded,
    // given the extensions below?
    memberwise init(...)
  }

  // in `ComplicatedClass+Foo.swift`
  extension ComplicatedClass {
    var fooData: Foo? = nil
    // presumably stuff-involving-`fooData`
  }

  // in `ComplicatedClass+Bar.swift`
  extension ComplicatedClass {
    var barData: Bar = Bar.standardBar
    // presumably stuff-involving-`barData`
  }

It doesn't seem impossible to specify how the memberwise-initialization would interact with constructs like the above, but I'd worry a bit about it making a feature that's already looking *rather* complicated even more so.

Especially since, if I had to pick just one, I'd think the ability to define stored properties outside the initial definition is a bigger win than a nice memberwise-initialization construct, even though both seem handy.

I followed the stored-properties-in-extensions discussion reasonably closely. My understanding is that the extension will need to initialize its own properties, either with an initial value or with a `partial init`. Designated initializers would be required to call the `partial init` for any extension that defines one.

This being the case, memberwise initialization would not directly interact with this feature at all. Memberwise initializers declared in the main body of type itself would only expose stored properties defined in the type itself.

It would also be possible to support `partial memberwise init` in extensions which would expose the stored properties declared in the extension as part of a partial initializer.

I don’t think there are difficult complications here.

Secondly, I’m a bit unsure how this will interact with e.g. the property-behavior proposal if both wind up ratified. For `lazy`, the interaction with `memberwise` is easy — it is omitted from the list — but when you get into e.g. something like a hypothetical `logged` or `synchronized` or `atomic` — wherein there is custom behavior, but the field would still need initialization — you’d want them to be included in the
`memberwise` init.

My thought here is that a behavior would define whether a property allows and / or requires initialization in phase 1 or not. This is probably necessary independent of memberwise initialization. Properties that allow or require phase 1 initialization would be eligible for memberwise initialization. Properties that don’t allow phase 1 initialization would not be eligible for memberwise initialization.

It’s a bit unfair to bring up another proposal, but this proposal and something like the property-behavior proposal *would* need to work well together (if both are approved).

Agreed. That is why there is a rule that references property behaviors in the proposal.

Thirdly, I’m not sure what the current plans are (if any) for users to be able to specify the precise memory-layout of a struct; apologies if this is already a feature, I simply haven’t looked into it.

**Today**: I order stored-field declarations for ease-of-reading (e.g. grouped into logical groups, and organized for ease-of-reading).

**Under Proposal**: I sometimes will get to choose between the “ease-of-reading” declaration ordering and the “cleanest-reading memberwise init” declaration ordering. These may not always be identical.

Agree. This is something that could be addressed in a future enhancement if necessary. This proposal is focused on the basic mechanism.

Also, nothing in the proposal prevents you from continuing to write a manual initializer when the synthesized initializer will not do what you require. If you are already explicitly restating the property identifiers to specify parameter order you are already half way to a manual initializer implementation.

Granted, if you need more than one memberwise initializer you would have to duplicate that effort. But re-ordering is going to have a hard time providing enough value if the basic feature does what we need in the majority of cases.

**Future?**: I may have to choose between the “ease-of-reading” declaration ordering, the “cleanest-reading member wise init” declaration ordering, and (perhaps?) the “intended memory-layout” declaration ordering.

I don’t want to make this proposal more-complicated than it already is, but I worry a bit about having too many things impacting the choice of how to order declarations in source files; it may be better to include a way to explicitly declare the ordering-for-memberwise:

E.G., some way of explicitly indicating the memberwise ordering, perhaps like this:

  // syntax example re-using `ComplicatedClass`
  class ComplicatedClass {
    @memberwise($parameterList)
    // ^ can use just @memberwise to get default ordering + the defaults from
    // the property declarations, but perhaps require the explicit listing
    // whenver the ordering is not well-defined (e.g. if you have properties
    // declared in extensions…then you need to order it yourself)
    //
    // @memberwise(text="Example",barData=,fooData)
    // - `text="Example"` => memberwise init has text="Example"
    // - `barData=` => memberwise init has `barData` w/out default
    // - `fooData` => memberwise init has `fooData` w/default if it has one
    //
    // …and e.g. the above would make:
    //
    // memberwise init(...)
    //
    // ...expand-to:
    //
    // init(text:String = "Example", barData: Bar, fooData:Foo?=nil)
    //
    // ...and with the @memberwise declaration supporting a `...` for `super`
    // placement, like so:
    //
    // // superclass members come before:
    // @memberwise(...,)
    // @memberwise(...,$parameterList)
    //
    // // superclass members come after
    // @memberwise(,...)
    // @memberwise($parameterList,...)
    //
    // ...perhaps with tweaked syntax (`@memberwise(...,$)` or `@memberwise(...,self)`)
    // to be bit easier to read when you don't have an explicit parameter list?
  }

...which of course potentially only-further complicates the feature in some ways, but avoids having this use of this feature *necessarily* impact how one might choose to order declarations?

On Jan 6, 2016, at 4:47 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift community,

The review of "Flexible Memberwise Initialization" begins now and runs through January 10th. The proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0018-flexible-memberwise-initialization.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

  https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  * What is your evaluation of the proposal?
  * Is the problem being addressed significant enough to warrant a change to Swift?
  * Does this proposal fit well with the feel and direction of Swift?
  * If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

  https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris
Review Manager
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

For the record (and independent of my dissent) it has always behaved this way. Access level of an implicit memberwise initializer is private if any stored property is private, internal otherwise.

Jordan

···

On Jan 8, 2016, at 15:07, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 8, 2016, at 2:09 PM, David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:

On Jan 8, 2016, at 11:21 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

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.

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.

Wow, you’re right. It is enforcing access control. The implicit init is internal if there are no private properties, but private if there are private properties. I wonder if this has changed. If not, I’m embarrassed that I didn’t understand the current behavior in detail.

I thought it was always internal. I’ve never actually used it for a struct with private properties before and I think the docs all say internal so maybe that is why. In any case, I’m glad to see that it is enforcing access control rules.

I’m not seeing this behavior, I’m seeing private always regardless of access level of the struct’s members. Xcode 7.2.

-David

···

On Jan 8, 2016, at 3:24 PM, Jordan Rose <jordan_rose@apple.com> wrote:

On Jan 8, 2016, at 15:07, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 8, 2016, at 2:09 PM, David Owens II <david@owensd.io <mailto:david@owensd.io>> wrote:

On Jan 8, 2016, at 11:21 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

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.

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.

Wow, you’re right. It is enforcing access control. The implicit init is internal if there are no private properties, but private if there are private properties. I wonder if this has changed. If not, I’m embarrassed that I didn’t understand the current behavior in detail.

I thought it was always internal. I’ve never actually used it for a struct with private properties before and I think the docs all say internal so maybe that is why. In any case, I’m glad to see that it is enforcing access control rules.

For the record (and independent of my dissent) it has always behaved this way. Access level of an implicit memberwise initializer is private if any stored property is private, internal otherwise.

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.

Maybe I wasn’t clear enough, but I never intended for all of them to be accepted. They are intended to show different ways to allow a bit more control.

The proposal only changes current state in a few ways:

1. Allow the memberwise initializer to be used in classes
2. Allow default parameter values for `var` properties
3. Fix the problem the current memberwise initializer has with lazy properties
4. Use the `set` rather than `get` visibility for `var` properties
5. Allow you to request the memberwise initializer, including:
  i. Specify access level, which will result in omission of memberwise parameters for more-private properties
  ii. Add additional parameters
  iii. include an initializer body

Are there specific changes in this list that you dislike?

No, I think you’re goal is reasonable and your proposal is well thought out. The problem comes down to the details on how to support it. Each point has a set of gotcha’s that require rules to handle properly.

It’s simply my opinion that these rules make the feature far too complicated.

You could go super basic and just have the proposal help address the struct scenario and have the default value for “var” members carried through to the implicitly created init().

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.

How is this more applicable than just for initialization? Are you suggesting a self parameter be allowed in any method and it would result in an immediate set of that property?

Yes, I’m suggesting that “self” is a qualifier, like “inout”.

This code:

struct Point {
    var x, y, z: Int
    init(self x: Int, self y: Int = 0, self z: Int = 0) {}
    func foo(self x: Int) {}
}

Would be identical to this code:

struct Point {
    var x, y, z: Int
    init(x: Int, y: Int = 0, z: Int = 0) {
        self.x = x; self.y = y; self.z = z;
        // rest of function
    }

    func foo(x: Int) {
        self.x = x
        // rest of function
    }
}

That assignment happens before the function body executes.

This model fixes the majority of my complexity issues. However, it brings some others to the table and doesn’t solve the need to duplicate all of the members in the API.

I think something like this was mentioned before, but I don’t remember what happened with it. However, another way to do initialization could be like this (C# calls this field initializers):

  let p = Point {
        x = 12,
        y = 13,
        z = 14
    }

We then get out of caring about the ordering of the parameters. However, this feature is much more narrow as it only applies to public properties. There is a lot of subtly in actually implementing this in the compiler though.

I really appreciate the feedback and conversation. I am continuing to think about all of the comments and am hoping we can come out of this review with a vision for a path forward that makes most people happy whether the proposal is accepted or not. (I think it’s clear that no solution will make everyone happy but do hope we can hit a sweet spot)

Just to be clear, I think the proposal lays out the land well and has good coverage of the issues. I just find it too complicated of a ruleset to need to know.

-David

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.

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.

Wow, you’re right. It is enforcing access control. The implicit init is internal if there are no private properties, but private if there are private properties. I wonder if this has changed. If not, I’m embarrassed that I didn’t understand the current behavior in detail.

I thought it was always internal. I’ve never actually used it for a struct with private properties before and I think the docs all say internal so maybe that is why. In any case, I’m glad to see that it is enforcing access control rules.

For the record (and independent of my dissent) it has always behaved this way. Access level of an implicit memberwise initializer is private if any stored property is private, internal otherwise.

Thanks for setting the record straight. I don't think any of the docs mention this and I had never tried it so I didn't realize this. It's a bit embarrassing as I feel like it is something I should have discovered while writing the proposal.

···

Sent from my iPad

On Jan 8, 2016, at 5:24 PM, Jordan Rose <jordan_rose@apple.com> wrote:

On Jan 8, 2016, at 15:07, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 8, 2016, at 2:09 PM, David Owens II <david@owensd.io> wrote:
On Jan 8, 2016, at 11:21 AM, Matthew Johnson <matthew@anandabits.com> wrote:

Jordan

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.

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.

Wow, you’re right. It is enforcing access control. The implicit init is internal if there are no private properties, but private if there are private properties. I wonder if this has changed. If not, I’m embarrassed that I didn’t understand the current behavior in detail.

I thought it was always internal. I’ve never actually used it for a struct with private properties before and I think the docs all say internal so maybe that is why. In any case, I’m glad to see that it is enforcing access control rules.

For the record (and independent of my dissent) it has always behaved this way. Access level of an implicit memberwise initializer is private if any stored property is private, internal otherwise.

I’m not seeing this behavior, I’m seeing private always regardless of access level of the struct’s members. Xcode 7.2.

That's weird. Always internal for me unless there is a private property. Xcode 7.2 as well.

···

Sent from my iPad

On Jan 8, 2016, at 5:34 PM, David Owens II <david@owensd.io> wrote:

On Jan 8, 2016, at 3:24 PM, Jordan Rose <jordan_rose@apple.com> wrote:

On Jan 8, 2016, at 15:07, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 8, 2016, at 2:09 PM, David Owens II <david@owensd.io> wrote:
On Jan 8, 2016, at 11:21 AM, Matthew Johnson <matthew@anandabits.com> wrote:

-David

Would you propose removing the current implicit memberwise initializer for structs on the same grounds?

No, it’s a much smaller feature surface. I would proposed promoting it from a simple, situational feature to something very generic — much like what Joe Groff is doing with “lazy.”

How exactly would you do this? I don’t understand what you think that would look like.

It would like what I sketched out in remainder of my previous message.

Making it more capable is what my proposal is attempting to do so I am confused by this statement.

Making it more capable is not what I’m talking about. Making it more generic and more flexible it is what I’m talking about.

The property behaviors proposal, at least as I understand it, could change “lazy” from being a language feature to being a library feature. In the language, lazy is replaced with something more flexible and generic, something that could give rise to other new features totally unrelated to laziness, but built from the same new building blocks.

The “memberwise” proposal, on the other hand, would be analogous to expanding the “lazy” feature at the language level, adding a bunch of new rules and behavior to it.

• • •

Based on your feedback, I’m not sure the central point of my review came across. I don’t think I can explain it better than I did in the review, but maybe others can find the words.

Here’s a sketch of that — not a proposal, total BS syntax, totally hypothetical:

    struct S {
        let s0, s1, s2: String
        private let i: Int

        init(anInt: Int, anotherInt: Int, otherArgs: Members.except(i)) {
            members = otherArgs // assigned members inferred from tuple item names
            i = anInt > anotherInt ? anInt : anotherInt
        }
    }

I’d be happy — happier! — with a solution like that, despite the modest additional keystrokes, because (1) members and Members would presumably have a more predictable behavior that’s easier to remember and to understand by reading, and (2) they’d be usable in other contexts:

    mutating func updateFrom(other: S) {
        self.members = other.except(i)
        i = anInt > anotherInt ? anInt : anotherInt
    }

…or heck, even this:

    mutating func updateTwoStrings(s0: String, s1: String) {
        members = arguments
    }

    mutating func updateTwoStrings(s0: String, s1: String, message: String) {
        print(message)
        members = arguments.except(message)
    }

OK, I concede I'm now brainstorming quite a feature list here:

members property that turns all (stored?) properties into a tuple,
Members property that returns the type of the above,
select / except operations on any tuple that create a new tuple by filtering keys,
assignment of a tuple to members that matches by tuple key (and the tuple can contain a subset of all properties),
some way of variadically expanding a tuple type in an arg list, and
arguments implicit variable that gives all func args as a tuple. (That last one’s not necessary to replace this proposal; just threw it in there because I’m brainstorming.)

That’s a lot! But all these feature are more independent, flexible, and transparent than the ones in the proposal. They (1) need not all be understood all at once, (2) have less implicit behavior and rules about corner cases, (3) thus have a simpler mental model and are easier to understand just by reading, and (4) provide more capabilities in a broader range of contexts.

I really don’t think the “members” computed tuple property is a workable solution for initializing `let` properties.

What not? All the static type information is there for the compiler to apply the same checks it does right now.

Any such property that was allowed to do so would not work outside an initializer anyway as it would try to mutate a `let` when you used it.

Well, yes, because instead of invisible magic, the “members = tuple” initialization behaves exactly like any other assignment.

I have also been thinking a lot about approaches that would be similar in some sense and build on a general purpose parameter forwarding mechanism. I have some ideas that I am going to work on fleshing out tonight.

That’s the sort of thing I’d be interested in seeing.

Cheers,

Paul

···

On Jan 8, 2016, at 5:41 PM, Matthew Johnson <matthew@anandabits.com> wrote:

On Jan 8, 2016, at 4:14 PM, Paul Cantrell <cantrell@pobox.com <mailto:cantrell@pobox.com>> wrote:

The members property should probably not be a tuple but a struct, thereby providing names for the values.
I think splitting this property into two (varMembers and letMembers) with a read-only property members tying both together for convenience (members.vars, members.lets).

I don't think the `members` tuple is a good alternative here. It looks good on paper, but think about what it actually would need to involve to match this proposal and its likely enhancements:

- It would need to have different elements at different levels of accessibility, and we would somehow have to select the right level for the matching initializer.
- It would need to include only properties *writable* at that level.
- It would need to include only stored properties.
- It would need to include only properties that are either `var`s or uninitialized `let`s.
- But we would need mechanisms to add items that have been excluded, and remove items that have been included.

Plus there's all the weirdness around using it to reassign constants.

Basically, once you've applied all of the specialized rules needed to make the `members` tuple work for memberwise initializers, is `members` still going to be useful for anything else? Frankly, I think the answer to that question is "No". So we end up designing something that's maybe 1/4 orthogonal instead of 0/4 orthogonal, but is also a lot less clear. In the end, I don't think that'll actually be a win.

···

--
Brent Royal-Gordon
Architechies

The members property should probably not be a tuple but a struct, thereby providing names for the values.
I think splitting this property into two (varMembers and letMembers) with a read-only property members tying both together for convenience (members.vars, members.lets).

I don't think the `members` tuple is a good alternative here. It looks good on paper, but think about what it actually would need to involve to match this proposal and its likely enhancements:

- It would need to have different elements at different levels of accessibility, and we would somehow have to select the right level for the matching initializer.

That’s a good point. Maybe some kind of type narrowing according to accessibility (probably explicit)?

- It would need to include only properties *writable* at that level.

Or maybe have both readable and writeable parts/views, i.e. members.readable and members.writable

- It would need to include only stored properties.

They would be included in a readable part/view, though.

- It would need to include only properties that are either `var`s or uninitialized `let`s.

That’s why I separated into vars and lets in my playground. This is already quite workable with regards to assignability if still a bit clunky.

- But we would need mechanisms to add items that have been excluded, and remove items that have been included.

Yes, that’s still a big question. This would again require some kind of type narrowing according to properties excluded.

Plus there's all the weirdness around using it to reassign constants.

That’s why I separated into varMembers and letMembers in my playground. No reassignment possible but assignment within initializers is fine.

Basically, once you've applied all of the specialized rules needed to make the `members` tuple work for memberwise initializers, is `members` still going to be useful for anything else? Frankly, I think the answer to that question is "No". So we end up designing something that's maybe 1/4 orthogonal instead of 0/4 orthogonal, but is also a

The missing things seem to be mostly
(1) type narrowing according to accessibility (e.g. "let x: public Foo“ would give x the type of Foo narrowed to the public interface even if more of Foo would be visible here)
(2) maybe type narrowing according to readability/writability
(3) type narrowing according to excluded properties (e.g. let x: S#without(s0) would give x the type of S narrowed to the interface where s0 does not appear)
(4) ability to spread a struct into a parameter list (the struct’s property names becoming the parameter names)

I don’t immediately see a general use case for the (1)+(3) but could imagine that (4) would be generally useful and maybe even (2).
Maybe someone else has an idea on their usefulness or maybe there is a completely different solution with a different feature set.

lot less clear. In the end, I don't think that'll actually be a win.

Yeah. Still brainstorming here :-)

-Thorsten

···

Am 09.01.2016 um 21:24 schrieb Brent Royal-Gordon <brent@architechies.com>:

* What is your evaluation of the proposal?

-1. I’ve always preferred explicit vs implicit/automatic behaviour and I think the this proposal ads too much complexity, syntax and keywords for a fairly small gain (for me).

* Is the problem being addressed significant enough to warrant a change to Swift?

First of all, I don’t that that initialisers are that problematic/tedious to write to warrant this proposal. But I also see this adding too much magic for the small gain.

Does this proposal fit well with the feel and direction of Swift?

No.

If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

No.

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More than a glance and quick reading, but less than an in-depth study :)

···

On 11 Jan 2016, at 22:21, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 11, 2016, at 1:44 PM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

Sorry to leave this over the weekend before getting back to you! Planning to respond here, then go catch up on the thread—a possibly questionable ordering of tasks, but one that ensures I will actually respond at all.

No problem. Thanks for responding!

- Given that these initializers are based on access control, is "public memberwise init(...)" different from "internal memberwise init(...)"? Can I put both in the same type?

If you have at least one internal property they would result in different signatures so would not be a duplicate declaration. The public memberwise init would obviously need to initialize the internal property somehow.

That's what I expected, just wanted to have it spelled out. Thanks.

It seems like a big, complicated feature that "does what you mean" only when it's first added and then becomes an impediment to any later change.

I can certainly sympathize with this. It is the big drawback of the automatic model. At the same time, this proposal builds on the existing memberwise init for structs and doesn’t really make the rules that much more complex. But it does make the feature more prevalent and visible, thus making it more important to understand the rules. And of course it could be argued that the current memberwise init is too complex as it is.

For the record, here is a concise list of how this proposal expands the current memberwise init:

1. Allow the memberwise initializer to be used in classes
2. Allow default parameter values for `var` properties
3. Fix the problem the current memberwise initializer has with lazy properties
4. Use the `set` rather than `get` visibility for `var` properties
5. Allow you to request the memberwise initializer, including:
  i. Add additional parameters
  ii. include an initializer body
  iii. Specify access level, which will result in omission of memberwise parameters for more-private properties (it would be reasonable to limit this to private and internal if concerns about allowing it to be public are a significant factor)

I am curious to hear your thoughts on which of these points are not desirable, and what your opinion is about the existing rules for the implicit memberwise init for structs.

I'm happy with 1, 2, and 3 as a separate proposal, or several separate proposals. (For 1 in particular, the restriction predates the access control model, but making it implicit would also interfere with inheriting designated initializers.) I'm not sure 4 is interesting enough, but sure.

Hmm, thought you had agreed with #4 in the discussion about that topic. That said, it is less important in the context of an `internal` or `private` implicit memberwise initializer.

The particular concern I have with 5 is that the most interesting use case to me is for 'public' (indeed, that's by far the majority of the requests for this we've seen in Radar, rdar://problem/18065955 <rdar://problem/18065955>), but that's also the most dangerous one if you have anything unusual going on: different access control, library evolution, etc. (i) and (ii) are mostly just extra features, but (iii) is where it gets weird.

I can certainly understand your concerns regarding `public` as well as (iii).

I’m hoping this proposal will be accepted even if some features are removed. Even if only 1-3 or 1-4 were accepted to improve the implicit memberwise initializer I would consider that a good thing.

(The next most common request related to this proposal is 1, memberwise inits for classes, mostly in simple cases. rdar://problem/16704095 <rdar://problem/16704095>)

For public memberwise inits, I think my discomfort ultimately comes down to "the order of stored properties in a class is not usually part of the class's ABI", and this makes it too easy to opt into that, and then too hard to explain which members and why. There's also the problem of wanting to tweak one parameter's behavior, and being unable to do that; having to build more features on top of this one to fix that seems like it's going in the wrong direction.

I hope you’ll take a look at the new proposals I submitted. I think they provide a better approach to providing this kind of control than the enhancements I included in this proposal. The Partial Initializers proposal might be the best one to look at first. It would effectively supersede the explicit memberwise initializers in this proposal with a more general purpose implementation.

I'm motivated to solve the tiny value struct case, the public C-like struct case, but I don't think I want this creeping into the interface of a public class. I'd rather go with the "annotation on parameters" solution (which would be a separate proposal, of course).

public struct Point {
  public var x: Double
  public var y: Double
  public init(self x: Double, self y: Double) {}
}

or

  public init(@assigned x: Double, @assigned y: Double) {}
  public init(self.x: Double, self.y: Double) {}
  // something else

I’ll ask you the same question I asked David about this approach: if the parameter must be explicitly related to a property for assignment, why should we repeat the type information (and default value information if it is a var)? Doesn’t it seem reasonable to omit the type?

I'm happy to come up with a syntax to omit the type and default value; I do still think the listing of parameters should be explicit. (And it should be obvious where it gets any type and default value from.)

Glad to hear you think we could omit the type and default value (but still allow for overriding the default value). I think as a sugar feature it needs to save as much as possible to pay its way.

Another idea along the lines of paying its way as much as possible: maybe if all parameters are “self” parameters you could specify that once at the function level rather than repeating it for every parameter. What do you think about that idea? Maybe something like an @self attribute:

@self public init(x, y) {}

I agree that it should be obvious where those come from - I think the type and default value would come from the property declaration. Is there anywhere else it could come from?

I think this feature could be useful. I just don’t see it as being a complete solution. It would combine with my new Partial Initializers proposal very nicely.

Matthew
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

The latter I'm afraid.

I was just discussing this design space with Chris Willmore, who's been working on revamping how our function type model works. If we move to a multiple-argument model for functions rather than the current every-function-takes-a-tuple-argument model, then we will likely need at least limited support for packing and unpacking tuples from and to arguments in order to avoid regressing at argument forwarding use cases. However, even that limited packing/unpacking functionality might be enough to seriously consider a more general magic "members" property as an alternative.

I don’t mind discussing an alternative using this approach. If we’re going to do that I think it must be clear how it would cover various intended use cases in detail. Specifically, how would we address:

1. Default parameter values (at least for `var` properties)
2. `let` properties: it seems pretty magical indeed if the computed `var` property exposing the tuple could be used to initialize a `let` property.
3. Partial memberwise initialization exposing a subset of members following some kind of “automatic” or “opt-in” model for determining the subset.

Is it correct to assume that part of the magic is an understanding of the magic properties that allows them to be used to initialize the properties corresponding to the tuple members?

One thing I think is worth considering is that there is magic required no matter what approach we adopt. The primary advantage of this approach seems to be that the magic / implicit properties might sometimes be useful outside of an initialization context. There could be other advantages depending on the details of what this approach looks like but its hard to tell without more specifics.

Matthew

···

On Jan 7, 2016, at 11:39 AM, Joe Groff <jgroff@apple.com> wrote:

On Jan 7, 2016, at 8:28 AM, Dave Abrahams <dabrahams@apple.com <mailto:dabrahams@apple.com>> wrote:

-Joe

Sent from my moss-covered three-handled family gradunza

On Jan 6, 2016, at 7:12 PM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

Sent from my iPad

On Jan 6, 2016, at 8:46 PM, Dave Abrahams <dabrahams@apple.com <mailto:dabrahams@apple.com>> wrote:

Sent from my moss-covered three-handled family gradunza

On Jan 6, 2016, at 5:47 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Jan 6, 2016, at 5:23 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 6, 2016, at 6:04 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 6, 2016, at 2:47 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift community,

The review of "Flexible Memberwise Initialization" begins now and runs through January 10th. The proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0018-flexible-memberwise-initialization.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

  https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  * What is your evaluation of the proposal?

It’s okay.

  * Is the problem being addressed significant enough to warrant a change to Swift?

I’m lukewarm about that. I have never found writing out the initializers I want to be a significant burden, and I find my code is better when they’re explicit. Every new feature increases the language's complexity and surface area, and I fear this one is not going to pay its way.

  * Does this proposal fit well with the feel and direction of Swift?

Yes, but I worry that it may be too early to add it. Other features in this space, like truly generic variadics, may well obsolete anything we do today. I’m not sure we should be designing convenience features that are likely to overlap with more general features coming down the road unless the inconvenience is very painful… which I personally don’t find it to be.

It isn’t clear to me how generic variadics might obsolete the functionality of this proposal. Can you elaborate on that?

Not sure if this is exactly what Dave has in mind, but an idea that comes to mind: we could say that structs and classes have a magic "members" tuple and typealias:

struct Foo {
  var x, y: Int

  // Implicit members
  typealias Members = (x: Int, y: Int)
  var members: Members {
    get { return (x: x, y: y) }
    set { (x, y) = newValue }
  }
}

With plausible future features for forwarding tuples as arguments, then the memberwise initializer could be implemented like this:

      // Say that a parameter declared 'x...' receives a tuple of arguments labeled according to its type,
      // like '**x' in Python
init(members...: Members) {
  self.members = members
}

And I think all your other use cases could be covered as well.

That's exactly what I had in mind. Thanks, Joe!

Is there any chance of generic variadics along these lines being part of Swift 3? Or is this down the road further?

Meanwhile, back on the topic of the "..." placeholder.

For me, it boils down to:
The addition of the "memberwise" keyword and associated behavior would stand on it's own, without the inclusion of the "..." placeholder syntax. (IMO)
Omitting the "..." placeholder syntax now wouldn't prevent it from being added later.
If you agree with those statements, then the principle of "smallest, incremental change <Swift.org - Contributing; [swift.org <http://swift.org/&gt;\] seems to imply that the placeholder should be removed from this proposal.

That's my opinion. Does the rest of the community feel that the "..." placeholder is a necessary part of this proposal?

Yes, I feel that the "..." placeholder is necessary. I cannot support a proposal that results in

memberwise init() {}

because that initializer very clearly takes no arguments! The "..." serves as a visual indicator for where the arguments go and I think that's important.

I agree. As soon as the idea of a placeholder was mentioned I immediately liked it. It is much more clear that additional parameters are synthesized.

Also, and though this isn't explicitly spelled out in the proposal it seems like a reasonable assumption to make, the existence of "..." lets me put it somewhere other than at the end of the arguments list, e.g.

memberwise init(..., foo: String) {}

Yes, you will be able to do this. I didn’t provide and example of this but it is spelled out in the detail design.

···

On Jan 7, 2016, at 3:34 PM, Kevin Ballard via swift-evolution <swift-evolution@swift.org> wrote:
On Thu, Jan 7, 2016, at 11:23 AM, Alex Johnson via swift-evolution wrote:

-Kevin Ballard

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

We will probably have warning flags eventually.

I don't know what makes you think so. The language has so far carefully avoided this, and we've heard some pretty strong statements from the core team against the idea of compiler flags and incompatible dialects.

···

--
Brent Royal-Gordon
Architechies

We will probably have warning flags eventually.

I don't know what makes you think so. The language has so far carefully avoided this, and we've heard some pretty strong statements from the core team against the idea of compiler flags and incompatible dialects.

Warning flags are much different than dialect flags.

Maybe we will get by without them, but there are plenty of legitimate reasons that different people want the compiler to tell them about different things in their code. An alternate possibility might be to put this kind of thing in an external tool that can be invoked as part of the build system.

Regardless of implementation, I think we are likely to see tools of some kind that integrate with the build system and highlight different issues for different teams.

···

On Jan 7, 2016, at 7:25 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

--
Brent Royal-Gordon
Architechies

Do you have an example of where you would want a caller to
initialize a property, but then overwrite the value they provide
*during initialization*?

Sure, how about something like a Rect type that always guarantees
it's in "standard" form (e.g. no negative sizes):

struct StandardRect { var origin: CGPoint var size: CGSize {
didSet { // ensure standardized form here } }

memberwise init(...) { if size.width < 0 {
origin.x += size.width size.width = -size.width }
if size.height < 0 { origin.y += size.height
size.height = -size.height } } }

This is a good example. Thanks!

Actually I do not like this example for several reasons: (1) I would
make the rectangle an immutable type with let properties, (2) the
didSet already seems to do what is encoded in the memberwise init, so
this seems to be redundant, (3) the memberwise init is so complex that
having the automatic initialization feature is not really worth it for
this example, especially as it seems to require using var properties
instead of let properties to do the overwriting.

1) Why would you make it immutable? That helps nothing and only serves
   to make the type harder to use. Structs should _rarely_ be immutable,
   you should always default to mutable and only make things immutable
   if there's a good reason for it. If the struct itself is in an
   immutable position then it inherits the immutability, which handles
   all of the reasons why you might otherwise default to immutable.

2) didSet isn't triggered in init. There's no redundancy.

3) You really really want var properties anyway, it's pointless to use
   let properties.

I think cases like this will be rare so I still think a warning is a
good idea. Something like -Wno-overwrite-memberwise-init would
allow it to be suppressed in cases where you actually do intend to
do this. Would that satisfy you?

No. It's not appropriate to have the only way to suppress a warning
on perfectly legal code to be passing a flag to the swiftc
invocation. Especially because we have no precedent yet for even
having flags like that.

What's wrong with the suggestion to make the warning behave the same
way as dead store warnings (e.g. warn if the property is overwritten
without any prior reads)? We already have logic for doing this kind
of analysis.

I think this would not be sufficient, because this would not allow
overwriting a property based on the value of another property which
might be necessary as well.

That seems much less likely to be necessary, because if you're doing
that, then you're completely ignoring one of your parameters.

Actually isn’t this what happens in your example? The property origin
is overwritten without being read, so this would generate the warning,
or did I understand something wrong?

Origin is being modified. Modification reads it first. `x += 2` reads
`x` before writing to it.

-Kevin Ballard

···

On Fri, Jan 8, 2016, at 12:56 AM, Thorsten Seitz wrote:

Am 08.01.2016 um 00:41 schrieb Kevin Ballard via swift-evolution <swift- >> evolution@swift.org>:
On Thu, Jan 7, 2016, at 03:11 PM, Matthew Johnson wrote:

On Jan 7, 2016, at 3:31 PM, Kevin Ballard <kevin@sb.org> wrote:
On Thu, Jan 7, 2016, at 07:12 AM, Matthew Johnson wrote:

After reading both your response below and also the proposal rather carefully, I agree that the possible issues I raised are all either not real issues or already addressed; thanks again for crafting the proposal and also for taking the time to reply to so much feedback.

That being said, I can’t shake a feeling that, overall, although I am definitely in favor of something along the lines of this proposal, in its concrete details at present this proposal isn’t really sitting anywhere near even a local-optimum on the `(flexibility,complexity) -> functionality` surface, as it were; it seems like both of these are possible:

- (a) make it a bit more flexible, for a high gain in functionality at a low incremental cost in complexity
- (b) make it a bit less flexible, for a modest loss in functionality and a large drop in complexity

…but for (b) it’s just a feeling and I don’t have a specific proposal (this may well be close to a minimum-viable-proposal for such a feature).

I agree with you.

As for (b) some people have suggested alternatives with less functionality like David’s `self propName: PropType` suggestion. So far I don’t think any of those add enough value over current state to be worth considering.

For (a) my sense is that although I can understand why you don’t want to even provide the option of specifying an explicit memberwise-parameter list, it really does seem that supporting at least an optional list makes it possible to get a lot more functionality for not much more *actual* complexity; this isn’t incompatible with also supporting an “automatic” option that uses the logic from the proposal where possible.

In terms of (a), I definitely agree that it would be desirable to allow for a bit more functionality. That is why I have suggested several enhancements. I don’t think we want all of them, but some are definitely desirable.

Chris really wanted to start with a core proposal and evaluate the enhancements independently, which is a good idea but also makes the proposal slightly less flexible than desirable. The enhancements I feel are most important are:

1. We need a way to specify a default value for memberwise parameters for `let` properties.
2. We need a little bit more control over which properties participate in memberwise initialization when the “automatic” rules don’t quite do the right thing for a particular use case. I think allowing distinct access control for `init` is the best way to handle this.

You mention specifying an explicit parameter list but don’t really elaborate further. Would the opt-in model described in the proposal meet what you have in mind? Or are you also consider with parameter order being independent of property declaration order?

I included a mock syntax in my initial response but it was (a) at the end and (b) perhaps a bit too terse. I have put a restated sketch at the bottom of this response.

Your example below hints at general parameter forwarding. I’ll elaborate further down.

Here’s a concrete example to illustrate why I’m harping on this point; I apologize for the length, but I think “small-n” examples can often give false intuition into how things will behave in real life:

Thank you for this! I probably should have provided at least one more concrete example myself. I am learning from that mistake in the second draft of my next proposal.

class FancyCollectionViewDriver : NSObject, UICollectionViewDataSource, UICollectionViewDelegate /*, etc... */ {
  
  let collectionView: UICollectionView
  let contentPresentation: ContentPresentation
  let modelBroker: ModelBroker
  let imageBroker: ImageBroker
  let analyticsSink: AnalyticsSink
  private(set) var currentData: ModelData
  private(set) weak var interactionDelegate: DriverDelegateProtocol?
  // ^ can't be non-optional `unowned let` for reasons,
  // but we expect a non-nil argument in init
  // NOTE: numerous private state-tracking variables omitted since we are only focusing on initialization

  // Present-day initializer, full of boilerplate:
  required init(
    collectionView: UICollectionView,
    contentPresentation: ContentPresentation,
    modelBroker: ModelBroker,
    imageBroker: ImageBroker,
    analyticsSink: AnalyticsSink,
    // note use of different argument name:
    initialData: ModelData,
    // note use of non-optional:
    interactionDelegate: DriverDelegateProtocol) {
      // oh boy here we go again:
      self.collectionView = collectionView
      self.contentPresentation = contentPresentation
      self.modelBroker = modelBroker
      self.imageBroker = imageBroker
      self.analyticsSink = analyticsSink
      self.currentData = initialData
      self.interactionDelegate = interactionDelegate
      super.init()
      // only non-assignment logic in the entire init:
      self.collectionView.dataSource = self
      self.collectionView.delegate = self
    }
    
    // best we can do under proposal w/out modifying
    // class design:
    required memberwise init(
    // lots of boilerplate gone:
    ...,
    // this isn't changed:
    initialData: ModelData,
    // this isn't changed:
    interactionDelegate: DriverDelegateProtocol) {
      // synthesized stuff is effectively here
      self.currentData = initialData
      self.interactionDelegate = interactionDelegate
      super.init()
      // only non-assignment logic in the entire init:
      self.collectionView.dataSource = self
      self.collectionView.delegate = self
    }
  
}

…which I do think is already a huge improvement.

And gets even better if we allow access control for init. Your `private(set)` members would now become eligible for memberwise initialization in an `internal` initializer because `init` has a distinct access level which defaults to `internal`.

Indeed, but please do note that I’d still like:
- `initialData` instead of `currentData`
- a non-nil `interactionDelegate` at init

That said, I feel that e.g. for any variable declaration syntax something like `private(set) internal(init=initialData) var currentData: ModelData` would be best avoided, even if it’d buy me the ability to customize the name in the synthesized memberwise init; it’s just too much and IMHO sets a bad precedent.

    required memberwise init(...) {
      // synthesized stuff is effectively here
      super.init()
      // only non-assignment logic in the entire init:
      self.collectionView.dataSource = self
      self.collectionView.delegate = self
    }

Now suppose that stored-properties-in-extensions hits (as the "partial-init" flavor); in that case I’d ideally be able to move some of the parts into their own files like so:

// in `FancyCollectionViewDriver+Analytics.swift`
extension FancyCollectionViewDriver {
  // ^ depending on advances in the protocol system, at some point may
  // evolve into a protocol-adoption to get useful default implementations
  
  let analyticsReporter: AnalyticsReporter
  // ^ moved here, not in main declaration
  // assume also a bunch of private state-tracking stuff...
  
  // a bunch of things like this:
  func reportEventTypeA(eventAInfo: EventAInfo)
  func reportEventTypeB(eventBInfo: BventAInfo)
  
}

// in `FancyCollectionViewDriver+Interaction.swift`
extension FancyCollectionViewDriver {
  
  private(set) var interactionDelegate: DriverDelegateProtocol?
  // ^ moved here, not in main declaration
  // assume also a bunch of private state-tracking stuff...
  
  // a bunch of things like this:
  func handleInteractionA(interactionAInfo: InteractionAInfo)
  func handleInteractionB(interactionBInfo: InteractionBInfo)
  
}

…(and so on for e.g. the `imageBroker` also), but under the current proposal this would put them outside the scope of a memberwise init (this isn’t news to you, I’m just making it concrete).

So in this scenario, we’re either reapproaching the MxN problem memberwise-init is meant to avoid:

init(
  // still save some boilerplate:
  …,
  imageBroker: ImageBroker,
  analyticsReporter: AnalyticsReporter,
  initialData: ModelData,
  interactionDelegate: DriverDelegateProtocol) {
  // some boilerplate synththesized here...
  // ...but getting closer to where we started:
  self.partial_init(imageBroker: imageBroker)
  self.partial_init(analyticsReporter: analyticsReporter)
  self.currentData = modelData
  self.partial_init(interactionDelegate: interactionDelegate)
  super.init()
  self.collectionView.dataSource = self
  self.collectionView.delegate = self
}

…or we’re making choices between taking full-advantage of properties-in-extensions (which IMHO would often be a *huge* readability win) versus taking full-advantage of boilerplate-reduction in our inits.

If extensions with stored properties are going to properly encapsulate their state (I believe this is the way to go) they are going to have to initialize state on their own and the primary initializer will have to provide arguments the initializer requires. Allowing stored properties in extensions automatically appear in a memberwise initializer violates that encapsulation.

"Automatic appearance" would definitely be bad; it’d seem like using such extensions would have to get you disqualified for automatic synthesis.

It’s still a tricky point though given the uncertainty about future directions; there seems to be some discussion of allowing protocols to define (instead of merely require) stored properties, which would perhaps be yet-another wrinkle to have to at least consider.

The good news is that a general parameter forwarding mechanism can help if the extension init (or super init) requires a bunch of arguments and you just want to forward them from your caller. This is alluded to in the enhancement section of the proposal but is really a completely general and orthogonal feature.

It might look something like this:

memberwise init(…superArgs, …partial1args, …partial2args, …memberwise) {
  extension1.init(directArgument: 42, …partial1args)
  extension2.init(…partial2args)
  super.init(…superArgs)
}

A couple things to note about how this might work:

1. The initializer calls (or function / method calls in other cases) must be unambiguous from the code alone.
2. Any parameters for which a direct argument is not provided are “captured” by the `…identifier` placeholder.
3. Parameters matching those captured by the identifier are synthesized in the location specified in the parameter list.

Obviously this won’t help if the extensions only require a single argument. But if you have extensions requiring several arguments that you want to pass through it would help

Which is ultimately why I suspect that the “right" version of the proposed feature should cut to the chase and incorporate some way to explicitly-specify the memberwise parameter list — which, again, need not be incompatible with the ability to request automatic synthesis using logic ~ what’s in the proposal — as such an explicit list takes the pressure off of getting the default behavior as-right-as-possible while also making it simpler to support some very nice-to-have capabilities not supported by this proposal as-written.

How would this be different than the opt-in model described in the proposal? Do you have something specific in mind?

This is what I had in the original. To expand what I meant a bit:

- you’d a type into “memberwise" by including `@memberwise` somewhere in the declaration
- `@memberwise` can be used two ways:
  - “bare" `@memberwise` => try to use the automatic approach (~ the logic in this proposal, or similar)
  - `@memberwise($parameterList)`, for explicit lists

…with some examples for the $parameterList in a second.

Assume a class like so:

class Example {
  let foo: Foo
  var bar: Bar = Bar.standard
  var baz: Baz = Baz.standard
}

Then here are some @memberwise declarations:

@memberwise => init(foo: Foo, bar: Bar = Bar.standard, baz: Baz = Baz.standard)
// ^ automatic, roughly ~ proposal

@memberwise(foo,bar,baz) => same as above
// ^ explicit, but identical

@memberwise(foo,baz,bar) => init(foo: Foo, baz: Baz = Baz.standard, bar: Bar = Bar.standard)
// ^ explicit, but reordered arguments

@memberwise(foo,bar=Foo.funkyAlternative,baz) => init(foo: Foo, bar: Bar = Bar.funkyAlternative, baz: Baz = Baz.standard)
// ^ explicit, alternate default for `bar`

@memberwise(foo,bar=,baz) => init(foo: Foo, bar: Bar, baz: Baz = Baz.standard)
// ^ explicit, suppress default for `bar`
// …”suppression" syntax isn’t great but it would seemingly work...

@memberwise(foo=Foo.common,bar,baz) => init(foo: Foo = Foo.common, bar: Bar = Bar.standard, baz: Baz = Baz.standard)
// ^ explicit, provide default for the `let`-property `foo`

…and perhaps even the ugly-but-serviceable renaming support like:

@memberwise(foo,bar,baz as initialBaz=) => init(foo: Foo, bar: Bar = Bar.standard, initialBaz: Baz)

…but not sure how to have a non-awful syntax for the case where you want to “promote” a property that’s internally optional to the non-optional case (or vice-versa I guess, or some more-general not-the-same type; that may be out-of-scope).

Note that something like the above would also offer a natural way to handle superclass initialization:

@memberwise(…,$parameterList) => this type’s parameters come *after* parent classes’ (memberwise) parameters
@memberwise($parameterList, ..) => this type’s parameters come *before* parent classes’ (memberwise) parameters

…although I’m not sure how often that’d come up in practice.

I explored inheritance quite a bit early on in the proposal. Chris convinced me that the right way to handle this is through a general parameter forwarding mechanism.

This is not a concrete proposal; it’s just a sketch of how an explicit parameter-list could be designed to still support the automatic approach when possible. I’m assuming that it’s a compiler error to have an explicit list that is either (a) incomplete or (b) has any invalid/unrecognized property names.

It also feels weird to have an @-style annotation *inside* a type, so there’s a lot of room to improve the proposed syntax.

And all the other arguments against the explicit list would also still apply, of course.

Are you suggesting that this attribute would be applied to a specific initializer? Or would this be shared by all memberwise initializers of the type in some way?

I don’t think applying this to a specific initializer gains enough over just writing the initializer manually to be worthwhile. If we were going to do something specific to a single initializer, something along the lines of David’s suggestion makes the most sense to me.

On the other hand, if you are suggesting something type-wide that would be shared by all memberwise initializers, this is really an alternate way to accomplish an opt-in model. Rather than applying an attribute to properties you would have a declaration specify which properties are included in memberwise initializers, with the ability to specify order, labels, and defaults if necessary.

That might be a reasonable syntax for an opt-in model. As noted in the proposal, an opt-in model could be added by a future enhancement and would be used in place of the automatic model if the opt-in syntax was present.

Matthew

···

On Jan 8, 2016, at 12:35 PM, plx via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 8, 2016, at 11:56 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On Jan 8, 2016, at 9:46 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

That’s my 2c; thanks to anyone who’s read through all this and thanks again for drafting a concrete-enough proposal to discuss properly.

Thanks for all your feedback and your example! I really appreciate it!

Matthew

On Jan 7, 2016, at 9:24 AM, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> wrote:

On Jan 7, 2016, at 9:02 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I like the general notion of something along these lines but admittedly haven’t had time to dig into the proposal specifics yet.

I have some concerns about cross-interactions with other features that are either also under discussion or are at least very anticipatable.

First, I know there has already been some discussion of allowing definition of stored fields in (some) extensions (e.g., something like allowing definition of stored fields in extensions within the module that defines the type).

E.G., something like this may become possible (assume all files are compiled together):

  // in `ComplicatedClass.swift`
  class ComplicatedClass {
    let text: String

    // how will this get expanded,
    // given the extensions below?
    memberwise init(...)
  }

  // in `ComplicatedClass+Foo.swift`
  extension ComplicatedClass {
    var fooData: Foo? = nil
    // presumably stuff-involving-`fooData`
  }

  // in `ComplicatedClass+Bar.swift`
  extension ComplicatedClass {
    var barData: Bar = Bar.standardBar
    // presumably stuff-involving-`barData`
  }

It doesn't seem impossible to specify how the memberwise-initialization would interact with constructs like the above, but I'd worry a bit about it making a feature that's already looking *rather* complicated even more so.

Especially since, if I had to pick just one, I'd think the ability to define stored properties outside the initial definition is a bigger win than a nice memberwise-initialization construct, even though both seem handy.

I followed the stored-properties-in-extensions discussion reasonably closely. My understanding is that the extension will need to initialize its own properties, either with an initial value or with a `partial init`. Designated initializers would be required to call the `partial init` for any extension that defines one.

This being the case, memberwise initialization would not directly interact with this feature at all. Memberwise initializers declared in the main body of type itself would only expose stored properties defined in the type itself.

It would also be possible to support `partial memberwise init` in extensions which would expose the stored properties declared in the extension as part of a partial initializer.

I don’t think there are difficult complications here.

Secondly, I’m a bit unsure how this will interact with e.g. the property-behavior proposal if both wind up ratified. For `lazy`, the interaction with `memberwise` is easy — it is omitted from the list — but when you get into e.g. something like a hypothetical `logged` or `synchronized` or `atomic` — wherein there is custom behavior, but the field would still need initialization — you’d want them to be included in the
`memberwise` init.

My thought here is that a behavior would define whether a property allows and / or requires initialization in phase 1 or not. This is probably necessary independent of memberwise initialization. Properties that allow or require phase 1 initialization would be eligible for memberwise initialization. Properties that don’t allow phase 1 initialization would not be eligible for memberwise initialization.

It’s a bit unfair to bring up another proposal, but this proposal and something like the property-behavior proposal *would* need to work well together (if both are approved).

Agreed. That is why there is a rule that references property behaviors in the proposal.

Thirdly, I’m not sure what the current plans are (if any) for users to be able to specify the precise memory-layout of a struct; apologies if this is already a feature, I simply haven’t looked into it.

**Today**: I order stored-field declarations for ease-of-reading (e.g. grouped into logical groups, and organized for ease-of-reading).

**Under Proposal**: I sometimes will get to choose between the “ease-of-reading” declaration ordering and the “cleanest-reading memberwise init” declaration ordering. These may not always be identical.

Agree. This is something that could be addressed in a future enhancement if necessary. This proposal is focused on the basic mechanism.

Also, nothing in the proposal prevents you from continuing to write a manual initializer when the synthesized initializer will not do what you require. If you are already explicitly restating the property identifiers to specify parameter order you are already half way to a manual initializer implementation.

Granted, if you need more than one memberwise initializer you would have to duplicate that effort. But re-ordering is going to have a hard time providing enough value if the basic feature does what we need in the majority of cases.

**Future?**: I may have to choose between the “ease-of-reading” declaration ordering, the “cleanest-reading member wise init” declaration ordering, and (perhaps?) the “intended memory-layout” declaration ordering.

I don’t want to make this proposal more-complicated than it already is, but I worry a bit about having too many things impacting the choice of how to order declarations in source files; it may be better to include a way to explicitly declare the ordering-for-memberwise:

E.G., some way of explicitly indicating the memberwise ordering, perhaps like this:

  // syntax example re-using `ComplicatedClass`
  class ComplicatedClass {
    @memberwise($parameterList)
    // ^ can use just @memberwise to get default ordering + the defaults from
    // the property declarations, but perhaps require the explicit listing
    // whenver the ordering is not well-defined (e.g. if you have properties
    // declared in extensions…then you need to order it yourself)
    //
    // @memberwise(text="Example",barData=,fooData)
    // - `text="Example"` => memberwise init has text="Example"
    // - `barData=` => memberwise init has `barData` w/out default
    // - `fooData` => memberwise init has `fooData` w/default if it has one
    //
    // …and e.g. the above would make:
    //
    // memberwise init(...)
    //
    // ...expand-to:
    //
    // init(text:String = "Example", barData: Bar, fooData:Foo?=nil)
    //
    // ...and with the @memberwise declaration supporting a `...` for `super`
    // placement, like so:
    //
    // // superclass members come before:
    // @memberwise(...,)
    // @memberwise(...,$parameterList)
    //
    // // superclass members come after
    // @memberwise(,...)
    // @memberwise($parameterList,...)
    //
    // ...perhaps with tweaked syntax (`@memberwise(...,$)` or `@memberwise(...,self)`)
    // to be bit easier to read when you don't have an explicit parameter list?
  }

...which of course potentially only-further complicates the feature in some ways, but avoids having this use of this feature *necessarily* impact how one might choose to order declarations?

On Jan 6, 2016, at 4:47 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello Swift community,

The review of "Flexible Memberwise Initialization" begins now and runs through January 10th. The proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0018-flexible-memberwise-initialization.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

  https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  * What is your evaluation of the proposal?
  * Is the problem being addressed significant enough to warrant a change to Swift?
  * Does this proposal fit well with the feel and direction of Swift?
  * If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

  https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris
Review Manager
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

My biggest problem is what does member wise even mean the averts person.
And a naked ... Is a spread operator in most languages and doesn't mean
anything inherently.

I worry about arguing about the specifics because this is way better than
the current state but I very much think the details of this proposal are
confusing to the average developer and is more restrictive to any future
use of the spread operator.

···

On Thu, Jan 7, 2016 at 8:25 PM Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

> We will probably have warning flags eventually.

I don't know what makes you think so. The language has so far carefully
avoided this, and we've heard some pretty strong statements from the core
team against the idea of compiler flags and incompatible dialects.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

So you know, I didn't really mean to put you specifically on the spot here; you're obviously trying to find concrete solutions to these problems. But it seems to me that what we're going to end up with is that, instead of having this:

  public init(members...: Members) {
    self.members = members
  }

We'll have something more like:

  public init(members...: Members.Public.Initializable) {
    self.members.public.initializable = members
  }

Which looks a whole lot worse than the original when you compare it to this proposal's:

  public memberwise init(...) {}

···

On Jan 10, 2016, at 1:17 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:
Yeah. Still brainstorming here :-)

--
Brent Royal-Gordon
Architechies

Yeah. Still brainstorming here :-)

So you know, I didn't really mean to put you specifically on the spot here; you're obviously trying to find concrete solutions to these problems. But it seems to me that what we're going to end up with is that, instead of having this:

   public init(members...: Members) {
       self.members = members
   }

We'll have something more like:

   public init(members...: Members.Public.Initializable) {
       self.members.public.initializable = members
   }

Which looks a whole lot worse than the original when you compare it to this proposal's:

   public memberwise init(...) {}

I think I have a solution to this which will be a good long-term direction with a clean migration path from the current proposal. I'll be posting details later today or tomorrow morning. I think you'll like it.

Matthew

···

Sent from my iPad
On Jan 10, 2016, at 3:37 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 10, 2016, at 1:17 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Yeah. Still brainstorming here :-)

So you know, I didn't really mean to put you specifically on the spot here; you're obviously trying to find concrete solutions to these problems.

No offense taken, I’m really interested in the opinion of everyone, that’s why I’m posting here :-)

But it seems to me that what we're going to end up with is that, instead of having this:

  public init(members...: Members) {
    self.members = members
  }

We'll have something more like:

  public init(members...: Members.Public.Initializable) {
    self.members.public.initializable = members
  }

Yes, that’s just what I’m trying to find out: I do like the Members-based idea but wanted to get a clearer understanding how it might *really* unfold before casting my vote for the current proposal.

Which looks a whole lot worse than the original when you compare it to this proposal's:

  public memberwise init(...) {}

You are certainly right, although one might argue that it has the advantage of spelling out a little bit more explicitly which members are hiding behind the "…“, i.e. it should be immediately clear that let properties with an initial value would not be part of Members.Public.Initializable, shouldn’t it?
Same for internal or private properties.
Whether that would be worth the longer form I’m not sure myself. At least it’s still just one simple assignment.

Exempting properties will certainly look even worse:

public init(members…: Members.Public.Initializable.except(i), x: Int) {
  self.members.public.initializable.except(i) = members
  i = 2 * x
}

In addition the syntax would need some changes to differentiate between regular property access, accessing the special property "members" and narrowing operations.

-Thorsten

···

Am 10.01.2016 um 10:37 schrieb Brent Royal-Gordon <brent@architechies.com>:

On Jan 10, 2016, at 1:17 AM, Thorsten Seitz <tseitz42@icloud.com> wrote: