[swift-evolution] [swift-evolution-announce] [Review] SE-0189: Restrict Cross-module Struct Initializers

Jordan Rose jordan_rose at apple.com
Fri Nov 17 19:57:41 CST 2017


> On Nov 17, 2017, at 15:20, Ben Langmuir <blangmuir at apple.com> wrote:
> 
> Hi Jordan,
> 
> First off, this is clearly the model we should have had all along ;-)  That said, I have a concern about source-compat and our ability to automatically migrate code impacted by this change.
>> Source compatibility
>> 
>> This makes existing code invalid in Swift 5, which is a source compatibility break.
>> 
> It's not just a source compatibility break, it's a break that cannot necessarily be fixed if you don't control the module that vended the struct.  If a library doesn't expose an appropriate initializer, there is no way for the client to invent one.  Similarly, this isn't going to be very amenable to automatic migration, since
> a) there may not be a memberwise initializer to use
> b) even if there is, it may change the semantics to use it
> 
> There are two classes that we could theoretically migrate automatically:
> 1) C structs, since we know the initializer and its semantics
> 2) when we are migrating the code that defines the struct at the same time
> 
> The latter case might be tricky though, since it requires more global knowledge than we have in today's migrator.
> 
> Any thoughts?  Do we have an idea how common this is or what kinds of places it comes up in most often (in a single codebase with multiple modules vs external dependencies vs C structs vs ....)?

This is good to bring up, but I think "this can't be migrated" is the correct answer for Swift structs. It's equivalent in my mind to when someone was passing 'nil' to something that wasn't annotated for nullability and now is marked '_Nonnull': it's source-breaking, and what you had before might even have worked, but there's no guarantee that it would keep working in the future. That's harder to sell for multi-module projects or even test targets, though. I don't have a great answer there, but I don't think it's worth bending over backwards to handle the "I migrate everything at once" case.

The C case is a bit harder to sell, which is why I made sure there were fix-its to suggest inserting `self.init()` (the zeroing initializer) in most cases (both in Swift 4 mode and Swift 5 mode). Not all C structs have that initializer (specifically, if they have a member marked _Nonnull), but nearly all do, and that's something the migrator could insert fairly easily, as you note.

The mitigating factor I'm hoping for is that these become warnings in Swift 4.1, which is planned to ship in a mid-year Xcode (can I admit that publicly, swift-evolution?), and that therefore many people will have cleaned up their code well before they even think of switching to Swift 5. But yes, this is a breaking, non-migratable language change that's only strictly necessary for libraries with binary compatibility, which most libraries today are not, and that has to be acknowledged.

Jordan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20171117/a46c67ad/attachment.html>


More information about the swift-evolution mailing list