It should be possible to generate public default initializers for structs

The generation of default initializers for Structs is a useful time-saving feature of Swift. In many cases, Structs are simply used as a collection of values, and it's incredibly convenient to get the initializer for free when defining the structure. This is especially true when dealing Structs with lots of members, for instance Codables which correspond to an externally-defined JSON specification.

This convenience is lost once a Struct must be used outside of the module in which it is declared. I understand the argument for this conceptually, that all decisions to make something public/open should be strictly opt-in. However in practice this is an aspect of Swift development which is frustrating, tedious, and counterintuitive.

For instance, here are a few examples of people running into this issue:

https://stackoverflow.com/questions/26224693/how-can-i-make-public-by-default-the-member-wise-initialiser-for-structs-in-swif

https://forums.swift.org/t/default-struct-initializer-internal-even-if-class-declared-public/4923

http://taylorfranklin.me/2016/07/10/the-default-memberwise-initializers-headache/

I can imagine a few different solutions to this problem:

  1. If a struct is public and only contains public members, it should have a public default initializer.

  2. Ann annotation should be available to make the default initializer public. (i.e. something like @defaultInitilizable struct Foo { ... })

In any case, something should be done about this as it adds significant friction when creating Swift libraries.

4 Likes

This type of feature was already been brought up for review, and was deferred. swift-evolution/0018-flexible-memberwise-initialization.md at master · apple/swift-evolution · GitHub

So I would advise, if you are serious about driving this type of feature forward, that you focus on refining parts of that proposal that were brought up during the review. You can also see the rationale for deferral. So I think follow on discussions should focus on the specific issues brought up in that.

I will say, though, now that Swift 5 is about to ship, I think this is something that we can seriously start looking at again.

2 Likes

I would be happy to revise and refocus SE-0018. One significant change I would make would be to focus exclusively on structs. I have learned a lot about how to approach SE since writing SE-0018. At the time I was aiming for a comprehensive feature that addressed all relevant aspects of the language. It’s now pretty clear that this is the wrong approach. Focusing on structs eliminates a lot of complexity and allows us to focus on the core functionality. After gaining experience with that, it would be possible to enhance the feature further to embrace classes if desired.

That said, I think the main impediment to moving forward on a return to SE-0018 is finding somebody willing to work on an implementation, as we can see with the current review of SE-0242. I would be thrilled to collaborate with anyone willing to work on an implementation!

11 Likes

I'd really like to see this feature since it would clean up my team's codebase a fair amount, but I've never contributed to Swift before. Matthew, if you haven't found anyone to help contribute to the implementation since Feb, I'm happy to poke around at it in my limited spare time unless someone else wants to step up. Let's chat!

(I also just linked to this post on one of the most popular StackOverflow questions on this topic to see if there are any other takers)

1 Like

@sethfri that is great to hear! I haven’t heard from anyone willing to help out yet and would love to work with you. Here’s a link to the latest thread on this topic Explicit Memberwise Initializers.

  1. This was rejected for the reasons given here: default struct initializer internal even if class declared public - #3 by DevAndArtist. Which is not to say that I'm necessarily against revisiting the matter, just that it might be a bit of an uphill battle.
  2. Personally I'd rather see syntax more like @synthesize(init) struct Foo { ... } (or struct Foo { ... } @synthesize(init)) because that provides a place to list all the things we want the compiler to synthesize for us. Even protocol conformances could be listed there, for things which the compiler can reason out for itself (Equatable, Hashable, and Codable all come to mind, although I suppose we couldn't actually require them to be listed there since it'd be a source-breaking change).
1 Like