[Review] SE-0018 Flexible Memberwise Initialization

using more generally useful language features I think we are going to eventually want for argument forwarding and compile-time metaprogramming anyway.

So how about just delaying everything for a while?
Imho there is no need to change the init-syntax overhasty, and afaics, this is a huge piece of work compared to other proposals.
It is much easier to use a little script that turns

let value: Int//=42
var x: Float?//!

into

let value: Int//=42
var x: Float?//!

init(value: Int = 42, x: Float) {
  self.value = value
  self.x = x
}

Nothing else can be as flexible and easy to understand at the same time, and the language itself can stay as it is until a convincing solution emerges.

Tino

I appreciate the thought that went into this memberwise-init proposal, and I’m in favor of eliminating boilerplate. However, the possibility that this functionality maybe addressed by generics, even if it’s only 75% addressed, makes me want to revisit this topic after generics are further along.

Matt

···

On Jan 7, 2016, at 10:28, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

Are there compelling reasons to go down this road rather than the current proposal? What use cases does it address that the current proposal does not?

I find this approach interesting because it enables the easy implementation of at least most memberwise initializers, using more generally useful language features I think we are going to eventually want for argument forwarding and compile-time metaprogramming anyway. If we had already had these features, would you still have been compelled to write your proposal?

-Joe

It’s a common use case to have a private stored object that’s set externally via the initializer, I think having a solution that doesn’t support that would be a big mistake.

IMO it would bad to expose a private property via an internal or public initializer without a specific request from the programmer to do that. I believe the best approach to address this is to allow access control for init: `private public(init)`.

Chris really wanted the initial proposal to focus on core functionality that can be enhanced later, with independent review of the enhancements, even if those enhancements make it into Swift 3. That is what this proposal reflects.

In the meantime, you can still do what you want using a memberwise initializer that manually accepts additional parameters for the private properties. That might not be ideal, but at least you can still use memberwise initialization for other properties.

Matthew

···

On Jan 8, 2016, at 10:09 AM, Tal Atlas <me@tal.by> wrote:

On Fri, Jan 8, 2016 at 11:08 AM Tal Atlas <me@tal.by <mailto:me@tal.by>> wrote:
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 <mailto: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 <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I like the idea of the proposal (not 100%) but i really dislike the "Future enhancements" part:

@default is unnecessary in my opinion, i think just write the "future" variable declaration ("memberwised") and put the default value is enough:

struct S {
    let s: String
    let i: Int

    // user declares:
    memberwise init(s: String = "hello",...) {}
    // compiler synthesizes:
    init(s: String = "hello", i: Int) { // because s: String matches the sintaxe, so the compiler will not (re)synthesize.
        /* synthesized */ self.s = s
        /* synthesized */ self.i = i
    }
}

This is not allowed under the proposal. If you declare a parameter with an external label matching a synthesized parameter an error will result. Allowing it would be one way to solve the default for `let` problem but it would require duplicating the parameter declaration and default value in every memberwise init.

···

On Jan 8, 2016, at 2:40 PM, Wallacy via swift-evolution <swift-evolution@swift.org> wrote:

memberwise properties and @nomemberwise are too much trouble for little gain. Hand write the init by itself will be more easy and clear.

The fist part when the proposal focuses only on the automation of (maybe only undeclared) variables on init using "..." placeholder as insertion point, I believe that can be a nice feature.

Em sex, 8 de jan de 2016 às 18:13, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> escreveu:

Am 08.01.2016 um 19:58 schrieb Kevin Ballard via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

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 <mailto: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 <mailto:kevin@sb.org>> wrote:

On Thu, Jan 7, 2016, at 07:12 AM, Matthew Johnson wrote:

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.

Hmm, food for thought… guess I still haven’t completely understood Swift’s handling of immutability… thanks for pointing that out!

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

You are right, of course. I forgot that when I wrote the mail.

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.

I stand corrected.

-Thorsten

-Kevin Ballard

_______________________________________________
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

I like the idea of the proposal (not 100%) but i really dislike the "Future
enhancements" part:

*@default* is unnecessary in my opinion, i think just write the "future"
variable declaration ("memberwised") and put the default value is enough:

struct S {
    let s: String
    let i: Int

    // user declares:
    memberwise init(s: String = "hello",...) {}

    // compiler synthesizes:
    init(s: String = "hello", i: Int) { // because s: String matches
the sintaxe, so the compiler will not (re)synthesize.
        /* synthesized */ self.s = s
        /* synthesized */ self.i = i
    }
}

*memberwise properties* and *@nomemberwise* are too much trouble for little
gain. Hand write the init by itself will be more easy and clear.

The fist part when the proposal focuses only on the automation of (maybe
only undeclared) variables on init using "..." placeholder as insertion
point, I believe that can be a nice feature.

···

Em sex, 8 de jan de 2016 às 18:13, Thorsten Seitz via swift-evolution < swift-evolution@swift.org> escreveu:

Am 08.01.2016 um 19:58 schrieb Kevin Ballard via swift-evolution < > swift-evolution@swift.org>:

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:

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.

Hmm, food for thought… guess I still haven’t completely understood Swift’s
handling of immutability… thanks for pointing that out!

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

You are right, of course. I forgot that when I wrote the mail.

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.

I stand corrected.

-Thorsten

-Kevin Ballard

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

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

"
This is not allowed under the proposal. If you declare a parameter with an
external label matching a synthesized parameter an error will result.
Allowing it would be one way to solve the default for `let` problem but it
would require duplicating the parameter declaration and default value in
every memberwise init.
"

Possibly you can then rethink this issue. Is more simpler than a new
operator. Also I see no reason to duplicate the parameter declaration in
other memberwise init. Less is more.

···

Em sex, 8 de jan de 2016 às 21:09, Matthew Johnson <matthew@anandabits.com> escreveu:

On Jan 8, 2016, at 2:40 PM, Wallacy via swift-evolution < > swift-evolution@swift.org> wrote:

I like the idea of the proposal (not 100%) but i really dislike the
"Future enhancements" part:

*@default* is unnecessary in my opinion, i think just write the "future"
variable declaration ("memberwised") and put the default value is enough:

struct S {
    let s: String
    let i: Int

    // user declares:
    memberwise init(s: String = "hello",...) {}

    // compiler synthesizes:
    init(s: String = "hello", i: Int) { // because s: String matches the sintaxe, so the compiler will not (re)synthesize.
        /* synthesized */ self.s = s
        /* synthesized */ self.i = i
    }
}

This is not allowed under the proposal. If you declare a parameter with
an external label matching a synthesized parameter an error will result.
Allowing it would be one way to solve the default for `let` problem but it
would require duplicating the parameter declaration and default value in
every memberwise init.

*memberwise properties* and *@nomemberwise* are too much trouble for
little gain. Hand write the init by itself will be more easy and clear.

The fist part when the proposal focuses only on the automation of (maybe
only undeclared) variables on init using "..." placeholder as insertion
point, I believe that can be a nice feature.

Em sex, 8 de jan de 2016 às 18:13, Thorsten Seitz via swift-evolution < > swift-evolution@swift.org> escreveu:

Am 08.01.2016 um 19:58 schrieb Kevin Ballard via swift-evolution < >> swift-evolution@swift.org>:

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:

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.

Hmm, food for thought… guess I still haven’t completely understood
Swift’s handling of immutability… thanks for pointing that out!

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

You are right, of course. I forgot that when I wrote the mail.

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.

I stand corrected.

-Thorsten

-Kevin Ballard

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

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

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

Partial initializers + forwarding is in line with what I’ve been imagining
as well. I look forward to seeing this fleshed out more.

Step Christopher
Big Nerd Ranch, LLC
schristopher@bignerdranch.com

···

On Sun, Jan 10, 2016 at 3:28 PM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

Sent from my iPhone

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

Unfortunately I’m in the wrong time zone: 8 pm CST means 3 am of the next
day here in Europe and I’d rather not get up in the middle of the night :-)
Bad luck that today you have dads duty but that’s life and there are more
important things than Swift evolution. I mean that sincerely, so don’t
worry about it.

I hadn’t expected a full draft of your vision, I just had hoped for one or
two lines to get an idea of your vision, no need to finish the draft for
that.

Hi Thorsten. I have time for a quick teaser. It may or may not mean much
without the details so watch for those tonight / in the morning.

The general approach I plan to outline uses partial initializers, concise
syntax for declaring memberwise partial initializers, a general parameter
forwarding mechanism, and sugar for directly forwarding to a partial
initializer. Obviously this is more than just one proposal.

There is a very clear and straightforward migration path from the current
proposal to the general solution if the necessary features are accepted.

More on this later tonight.

Matthew

But I understand that now is a bad moment to send me something, so no
worries. Have a nice day with your son!

-Thorsten

Am 10.01.2016 um 16:35 schrieb Matthew Johnson <matthew@anandabits.com>:

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

Hi Matthew,

Am 10.01.2016 um 15:03 schrieb Matthew Johnson <matthew@anandabits.com>:

On Jan 10, 2016, at 4:08 AM, Thorsten Seitz via swift-evolution < > swift-evolution@swift.org> wrote:

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

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.

I will be sharing my vision for a long-term direction later today or
tomorrow. It allows us to accept this proposal as a step forward while
still having a long-term path that relies on more general features, with a
clean migration path when the more general features are ready.

That sounds great! Would you mind sharing a sketch of your idea today just
to get a rough feeling before the review ends?

I would like to. I need a little bit more time to finish the drafts
before sharing. I have dad duty on Sundays so I won't be able to do that
until until my son goes to bed. I am hoping to be ready to share them by
about 8 or 9 CST tonight. That still leaves a few hours while the review
is open.

Matthew

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

Thanks!!

-Thorsten

···

Am 10.01.2016 um 21:28 schrieb Matthew Johnson <matthew@anandabits.com>:

Sent from my iPhone

On Jan 10, 2016, at 11:20 AM, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Unfortunately I’m in the wrong time zone: 8 pm CST means 3 am of the next day here in Europe and I’d rather not get up in the middle of the night :-)
Bad luck that today you have dads duty but that’s life and there are more important things than Swift evolution. I mean that sincerely, so don’t worry about it.

I hadn’t expected a full draft of your vision, I just had hoped for one or two lines to get an idea of your vision, no need to finish the draft for that.

Hi Thorsten. I have time for a quick teaser. It may or may not mean much without the details so watch for those tonight / in the morning.

The general approach I plan to outline uses partial initializers, concise syntax for declaring memberwise partial initializers, a general parameter forwarding mechanism, and sugar for directly forwarding to a partial initializer. Obviously this is more than just one proposal.

There is a very clear and straightforward migration path from the current proposal to the general solution if the necessary features are accepted.

More on this later tonight.

Matthew

But I understand that now is a bad moment to send me something, so no worries. Have a nice day with your son!

-Thorsten

Am 10.01.2016 um 16:35 schrieb Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>>:

On Jan 10, 2016, at 9:26 AM, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Hi Matthew,

Am 10.01.2016 um 15:03 schrieb Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>>:

On Jan 10, 2016, at 4:08 AM, Thorsten Seitz via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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

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.

I will be sharing my vision for a long-term direction later today or tomorrow. It allows us to accept this proposal as a step forward while still having a long-term path that relies on more general features, with a clean migration path when the more general features are ready.

That sounds great! Would you mind sharing a sketch of your idea today just to get a rough feeling before the review ends?

I would like to. I need a little bit more time to finish the drafts before sharing. I have dad duty on Sundays so I won't be able to do that until until my son goes to bed. I am hoping to be ready to share them by about 8 or 9 CST tonight. That still leaves a few hours while the review is open.

Matthew

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.

-Joe

···

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

On Jan 7, 2016, at 12:51 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

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

On Jan 7, 2016, at 12:37 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Jan 7, 2016, at 10:32 AM, David Owens II <david@owensd.io <mailto:david@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.

The appearance attributes probably won’t change within an app (would be strange to have the FontPicker sometimes have this font size then that, even stranger regarding the colors) but would only be different between different apps, or at least not change alone but in concert with all other UIControls.
So wouldn’t it be more appropriate for this example to instead use the existing UIAppearance functionality? Then the memberwise initializer would not really be needed here as configuring the appearance would not be done in the initializer.

-Thorsten

···

Am 07.01.2016 um 20:30 schrieb Matthew Johnson via swift-evolution <swift-evolution@swift.org>:

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.

This proposal recalls me some Java memory. How about to borrow the instance
fields init-expo and initializer rule and save one keyword.

Java language has class initializer and instance initializer:
class MyClass {
  private static String classField = "foo";
  private String instanceField = "bar";
  static { ... } // class initalizer
  { ... }
  MyClass() { } // constructor
}

init expr of class fields will be combined with class initializer, it will
be called when class is loading.

init expr of instance fields will be combined with instance initializer and
be called by every constructor.

···

On Sat, Jan 9, 2016 at 11:00 AM, Wallacy via swift-evolution < swift-evolution@swift.org> wrote:

"
This is not allowed under the proposal. If you declare a parameter with
an external label matching a synthesized parameter an error will result.
Allowing it would be one way to solve the default for `let` problem but it
would require duplicating the parameter declaration and default value in
every memberwise init.
"

Possibly you can then rethink this issue. Is more simpler than a new
operator. Also I see no reason to duplicate the parameter declaration in
other memberwise init. Less is more.

Em sex, 8 de jan de 2016 às 21:09, Matthew Johnson <matthew@anandabits.com> > escreveu:

On Jan 8, 2016, at 2:40 PM, Wallacy via swift-evolution < >> swift-evolution@swift.org> wrote:

I like the idea of the proposal (not 100%) but i really dislike the
"Future enhancements" part:

*@default* is unnecessary in my opinion, i think just write the "future"
variable declaration ("memberwised") and put the default value is enough:

struct S {
    let s: String
    let i: Int

    // user declares:
    memberwise init(s: String = "hello",...) {}

    // compiler synthesizes:
    init(s: String = "hello", i: Int) { // because s: String matches the sintaxe, so the compiler will not (re)synthesize.
        /* synthesized */ self.s = s
        /* synthesized */ self.i = i
    }
}

This is not allowed under the proposal. If you declare a parameter with
an external label matching a synthesized parameter an error will result.
Allowing it would be one way to solve the default for `let` problem but it
would require duplicating the parameter declaration and default value in
every memberwise init.

*memberwise properties* and *@nomemberwise* are too much trouble for
little gain. Hand write the init by itself will be more easy and clear.

The fist part when the proposal focuses only on the automation of (maybe
only undeclared) variables on init using "..." placeholder as insertion
point, I believe that can be a nice feature.

Em sex, 8 de jan de 2016 às 18:13, Thorsten Seitz via swift-evolution < >> swift-evolution@swift.org> escreveu:

Am 08.01.2016 um 19:58 schrieb Kevin Ballard via swift-evolution < >>> swift-evolution@swift.org>:

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:

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.

Hmm, food for thought… guess I still haven’t completely understood
Swift’s handling of immutability… thanks for pointing that out!

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

You are right, of course. I forgot that when I wrote the mail.

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.

I stand corrected.

-Thorsten

-Kevin Ballard

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

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

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

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

--
Best Regards!

Yang Wu
--------------------------------------------------------
Location: Pudong, Shanghai, China.
EMail : pinxue@gmail.com
Website: http://www.time2change.mobi http://rockplayer.com
Twitter/Weibo : @pinxue
<http://www.pinxue.net>

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

···

On Jan 7, 2016, at 8:30 PM, Joe Groff <jgroff@apple.com> wrote:

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

On Jan 7, 2016, at 12:51 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

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

On Jan 7, 2016, at 12:37 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Jan 7, 2016, at 10:32 AM, David Owens II <david@owensd.io <mailto:david@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.

One thing I should have mentioned in the reply last night is that the problem of breaking the memberwise initializers when access control changes is solvable. Several of the possible enhancements are attempts to allow the programmer to be more explicit when the rules don’t do the right thing. The breakage you describe is an example where that would be necessary.

The solution I believe is the best one (assuming the automatic model) is allowing distinct access control for initialization. Initialization is conceptually distinct from both getting and setting. We already allow programmers to specify distinct access levels for `get` and `set` (for `var`), but we don’t for `init`. It feels like a natural extension of the access control model to allow a distinction for initialization. The `init` access level could also be used in phase 1 for manually written initializers, rather than the `get` visibility of a `let` property and the `set` visibility of a `var` that is used today.

It would solve the problem problem you mention above by allowing the access control to be specified as `internal private(init)` rather than just `internal`. This access control change would have no impact on memberwise initializers.

This would also solve the problem you mentioned earlier that `let` properties more capable than `private(set) var` properties. It would no longer be necessary to use the `set` access level because there would be a distinct access level for `init`. In that case, the programmer could specify exactly what is desired:

1. `public private(set)` would allow public memberwise initializers to synthesize a parameter for the property
2. `private public(get)` would only allow private memberwise initializers to synthesize a parameter for the property. Only the getter would be visible publicly.
3. `public private(init)` would only allow private memberwise initializers to synthesize a parameter for the property. Both the getter and setter would be visible publicly.

Ultimately, I think the automatic model is only a good idea if we enforce access control. Allowing the distinction to be made solves the problems you have pointed out while also allowing the programmer to get the desired behavior out of the automatic model in most or all cases. For those reasons I think it would be a significant improvement over the current proposal.

Matthew

···

On Jan 7, 2016, at 8:30 PM, Joe Groff <jgroff@apple.com> wrote:

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

On Jan 7, 2016, at 12:51 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

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

On Jan 7, 2016, at 12:37 PM, Joe Groff <jgroff@apple.com <mailto:jgroff@apple.com>> wrote:

On Jan 7, 2016, at 10:32 AM, David Owens II <david@owensd.io <mailto:david@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.

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.

The appearance attributes probably won’t change within an app (would be strange to have the FontPicker sometimes have this font size then that, even stranger regarding the colors) but would only be different between different apps, or at least not change alone but in concert with all other UIControls.

An example of where it would change inside the app is with light and dark appearance modes. It may also change as the app evolves over time and the programmer might not want to hard code appearance attributes in the UI widget itself.

So wouldn’t it be more appropriate for this example to instead use the existing UIAppearance functionality? Then the memberwise initializer would not really be needed here as configuring the appearance would not be done in the initializer.

Not everyone likes UIAppearance, especially for custom widgets. Even if you do, it may not always be the best solution. Sometimes it is simpler and more clear to provide appearance attributes directly.

Aside from that, this was just an example. Similar structure often appears in view controllers where the properties that would be memberwise initialized would include data to display, etc.

Matthew

···

On Jan 8, 2016, at 3:22 AM, Thorsten Seitz <trsfoo@googlemail.com> wrote:

Am 07.01.2016 um 20:30 schrieb Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>: