Renamed types (Swift 3/4 Mix-and-Match)


(Jordan Rose) #1

TLDR: Should we just always import C/ObjC types under their Swift 4 names, and use typealiases in Swift 3 mode?

···

---

Hi, swift-dev. As my recent PRs have probably indicated, I've been working on the problems that can come up when mixing Swift 3 and Swift 4 code. Most of these problems have to do with C/ObjC APIs that might present themselves differently in Swift 3 and Swift 4, using the "API notes" feature in our downstream branch of Clang, and a good subset of these problems have to do with types getting renamed. (This includes being "renamed" into a member, such as NSNotificationName becoming (NS)Notification.Name in Swift.)

What's the problem? Well, there are a few. First of all, an API defined in terms of the Swift 3 name should still be callable in Swift 4. As an example, let's pretend NSNotification.Name was going to be renamed NSNotification.Identifier in Swift 4.

// Swift 3 library
public func postTestNotification(named name: NSNotification.Name) { … }

// Swift 4 app
let id: Notification.Identifier = …
postTestNotification(named: id) // should work

This means the reference to "NSNotification.Name" in the library's swiftmodule needs to still be resolvable. This isn't too bad if we leave behind a typealias for 'NSNotification.Name'. I have a reasonable (but too broad) implementation at https://github.com/apple/swift/pull/8737.

That just leads us to another problem, though: because Swift functions can be overloaded, the symbol name includes the type, and the type has changed. The Swift 3 library exposes a symbol '_T03Lib20postTestNotificationySo14NSNotificationC4NameV5named_tF', but the Swift 4 client expects '_T03Lib20postTestNotificationySo14NSNotificationC10IdentifierV5named_tF'.

My planned approach to combat this was to use the C name of the type in the mangling, producing '_T03Lib20postTestNotificationySo18NSNotificationNamea5named_tF'. This is prototyped in https://github.com/apple/swift/pull/8871.

At this point Slava pointed out I was chasing down a lot of issues when there's a much simpler solution for Swift 4: when importing types, always use the Swift 4 name, and use typealiases to handle Swift 3 compatibility. This defines both of the previous issues away, as well as any more that I just haven't thought of yet.

There are some downsides:
- We currently keep people from using Swift 4 names in Swift 3 code, and we wouldn't be able to do that, since the actual declaration of the type always needs to be available.
- We'd probably want to tweak the "aka" printing in diagnostics to not look through these typealiases. That's not hard, though.
- We can't keep doing this once we have ABI stability. Hopefully framework owners aren't going to continue changing Swift names of types, but we'll probably need to implement my "C name in the mangling" plan anyway, just in case.

What do people think?

Jordan


(Jordan Rose) #2

Oh, I forgot there's one more option for fixing the mangling issue: save all mangled names into the swiftmodule. That also doesn't work once we have ABI stability, though, because you need to match the name for the previous release as well as the current one.

Jordan

···

On Apr 20, 2017, at 16:55, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:

TLDR: Should we just always import C/ObjC types under their Swift 4 names, and use typealiases in Swift 3 mode?

---

Hi, swift-dev. As my recent PRs have probably indicated, I've been working on the problems that can come up when mixing Swift 3 and Swift 4 code. Most of these problems have to do with C/ObjC APIs that might present themselves differently in Swift 3 and Swift 4, using the "API notes" feature in our downstream branch of Clang, and a good subset of these problems have to do with types getting renamed. (This includes being "renamed" into a member, such as NSNotificationName becoming (NS)Notification.Name in Swift.)

What's the problem? Well, there are a few. First of all, an API defined in terms of the Swift 3 name should still be callable in Swift 4. As an example, let's pretend NSNotification.Name was going to be renamed NSNotification.Identifier in Swift 4.

// Swift 3 library
public func postTestNotification(named name: NSNotification.Name) { … }

// Swift 4 app
let id: Notification.Identifier = …
postTestNotification(named: id) // should work

This means the reference to "NSNotification.Name" in the library's swiftmodule needs to still be resolvable. This isn't too bad if we leave behind a typealias for 'NSNotification.Name'. I have a reasonable (but too broad) implementation at https://github.com/apple/swift/pull/8737.

That just leads us to another problem, though: because Swift functions can be overloaded, the symbol name includes the type, and the type has changed. The Swift 3 library exposes a symbol '_T03Lib20postTestNotificationySo14NSNotificationC4NameV5named_tF', but the Swift 4 client expects '_T03Lib20postTestNotificationySo14NSNotificationC10IdentifierV5named_tF'.

My planned approach to combat this was to use the C name of the type in the mangling, producing '_T03Lib20postTestNotificationySo18NSNotificationNamea5named_tF'. This is prototyped in https://github.com/apple/swift/pull/8871.

At this point Slava pointed out I was chasing down a lot of issues when there's a much simpler solution for Swift 4: when importing types, always use the Swift 4 name, and use typealiases to handle Swift 3 compatibility. This defines both of the previous issues away, as well as any more that I just haven't thought of yet.

There are some downsides:
- We currently keep people from using Swift 4 names in Swift 3 code, and we wouldn't be able to do that, since the actual declaration of the type always needs to be available.
- We'd probably want to tweak the "aka" printing in diagnostics to not look through these typealiases. That's not hard, though.
- We can't keep doing this once we have ABI stability. Hopefully framework owners aren't going to continue changing Swift names of types, but we'll probably need to implement my "C name in the mangling" plan anyway, just in case.

What do people think?


(Philippe Hausler) #3

I see your conundrum here! Thats definitely a gnarly issue - I would say the preferred way seems much more to the C name of the symbol, but that does have a problem that might be possible. In your example the swift 4 name was Notification.Identifier, that would mean that it is possible for a developer to use then the old name somehow. Is this something we should watch out for? Specifically I am more so interested if it is something we should watch out for overlay development.

Per your idea about the type alias, shouldn’t we have an effective

@availability(swift, obsoleted: 4.0)
typealias NSNotification.Name = Notification.Identifier

To prevent source compatibility issues?

···

On Apr 20, 2017, at 16:55, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:

TLDR: Should we just always import C/ObjC types under their Swift 4 names, and use typealiases in Swift 3 mode?

---

Hi, swift-dev. As my recent PRs have probably indicated, I've been working on the problems that can come up when mixing Swift 3 and Swift 4 code. Most of these problems have to do with C/ObjC APIs that might present themselves differently in Swift 3 and Swift 4, using the "API notes" feature in our downstream branch of Clang, and a good subset of these problems have to do with types getting renamed. (This includes being "renamed" into a member, such as NSNotificationName becoming (NS)Notification.Name in Swift.)

What's the problem? Well, there are a few. First of all, an API defined in terms of the Swift 3 name should still be callable in Swift 4. As an example, let's pretend NSNotification.Name was going to be renamed NSNotification.Identifier in Swift 4.

// Swift 3 library
public func postTestNotification(named name: NSNotification.Name) { … }

// Swift 4 app
let id: Notification.Identifier = …
postTestNotification(named: id) // should work

This means the reference to "NSNotification.Name" in the library's swiftmodule needs to still be resolvable. This isn't too bad if we leave behind a typealias for 'NSNotification.Name'. I have a reasonable (but too broad) implementation at https://github.com/apple/swift/pull/8737.

That just leads us to another problem, though: because Swift functions can be overloaded, the symbol name includes the type, and the type has changed. The Swift 3 library exposes a symbol '_T03Lib20postTestNotificationySo14NSNotificationC4NameV5named_tF', but the Swift 4 client expects '_T03Lib20postTestNotificationySo14NSNotificationC10IdentifierV5named_tF'.

My planned approach to combat this was to use the C name of the type in the mangling, producing '_T03Lib20postTestNotificationySo18NSNotificationNamea5named_tF'. This is prototyped in https://github.com/apple/swift/pull/8871.

At this point Slava pointed out I was chasing down a lot of issues when there's a much simpler solution for Swift 4: when importing types, always use the Swift 4 name, and use typealiases to handle Swift 3 compatibility. This defines both of the previous issues away, as well as any more that I just haven't thought of yet.

There are some downsides:
- We currently keep people from using Swift 4 names in Swift 3 code, and we wouldn't be able to do that, since the actual declaration of the type always needs to be available.
- We'd probably want to tweak the "aka" printing in diagnostics to not look through these typealiases. That's not hard, though.
- We can't keep doing this once we have ABI stability. Hopefully framework owners aren't going to continue changing Swift names of types, but we'll probably need to implement my "C name in the mangling" plan anyway, just in case.

What do people think?

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


(Michael Ilseman) #4

TLDR: Should we just always import C/ObjC types under their Swift 4 names, and use typealiases in Swift 3 mode?

---

Hi, swift-dev. As my recent PRs have probably indicated, I've been working on the problems that can come up when mixing Swift 3 and Swift 4 code. Most of these problems have to do with C/ObjC APIs that might present themselves differently in Swift 3 and Swift 4, using the "API notes" feature in our downstream branch of Clang, and a good subset of these problems have to do with types getting renamed. (This includes being "renamed" into a member, such as NSNotificationName becoming (NS)Notification.Name in Swift.)

What's the problem? Well, there are a few. First of all, an API defined in terms of the Swift 3 name should still be callable in Swift 4. As an example, let's pretend NSNotification.Name was going to be renamed NSNotification.Identifier in Swift 4.

// Swift 3 library
public func postTestNotification(named name: NSNotification.Name) { … }

// Swift 4 app
let id: Notification.Identifier = …
postTestNotification(named: id) // should work

This means the reference to "NSNotification.Name" in the library's swiftmodule needs to still be resolvable. This isn't too bad if we leave behind a typealias for 'NSNotification.Name'. I have a reasonable (but too broad) implementation at https://github.com/apple/swift/pull/8737.

That just leads us to another problem, though: because Swift functions can be overloaded, the symbol name includes the type, and the type has changed. The Swift 3 library exposes a symbol '_T03Lib20postTestNotificationySo14NSNotificationC4NameV5named_tF', but the Swift 4 client expects '_T03Lib20postTestNotificationySo14NSNotificationC10IdentifierV5named_tF'.

My planned approach to combat this was to use the C name of the type in the mangling, producing '_T03Lib20postTestNotificationySo18NSNotificationNamea5named_tF'. This is prototyped in https://github.com/apple/swift/pull/8871.

At this point Slava pointed out I was chasing down a lot of issues when there's a much simpler solution for Swift 4: when importing types, always use the Swift 4 name, and use typealiases to handle Swift 3 compatibility. This defines both of the previous issues away, as well as any more that I just haven't thought of yet.

There are some downsides:
- We currently keep people from using Swift 4 names in Swift 3 code, and we wouldn't be able to do that, since the actual declaration of the type always needs to be available.

I don’t know if this is an important distinction to worry about. That code will still be able to use features from Swift 4, and perhaps even Swift 4 only types (e.g. Substring from SE-0163).

- We'd probably want to tweak the "aka" printing in diagnostics to not look through these typealiases. That's not hard, though.
- We can't keep doing this once we have ABI stability. Hopefully framework owners aren't going to continue changing Swift names of types, but we'll probably need to implement my "C name in the mangling" plan anyway, just in case.

Would this fall under the realm of library evolution, wherein name changes should be versioned? In that case, would we need both symbols whether they came from C or not?

···

On Apr 20, 2017, at 4:55 PM, Jordan Rose via swift-dev <swift-dev@swift.org> wrote:

What do people think?

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


(Jordan Rose) #5

Ah, we definitely will do that in Swift 4 mode no matter what approach is chosen here, since Swift 4 Is The Future. We also currently do that but in reverse for Swift 3 mode, using `@available(swift, introduced: 4)`.

Jordan

···

On Apr 20, 2017, at 17:09, Philippe Hausler <phausler@apple.com> wrote:

I see your conundrum here! Thats definitely a gnarly issue - I would say the preferred way seems much more to the C name of the symbol, but that does have a problem that might be possible. In your example the swift 4 name was Notification.Identifier, that would mean that it is possible for a developer to use then the old name somehow. Is this something we should watch out for? Specifically I am more so interested if it is something we should watch out for overlay development.

Per your idea about the type alias, shouldn’t we have an effective

@availability(swift, obsoleted: 4.0)
typealias NSNotification.Name = Notification.Identifier

To prevent source compatibility issues?

On Apr 20, 2017, at 16:55, Jordan Rose via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

TLDR: Should we just always import C/ObjC types under their Swift 4 names, and use typealiases in Swift 3 mode?

---

Hi, swift-dev. As my recent PRs have probably indicated, I've been working on the problems that can come up when mixing Swift 3 and Swift 4 code. Most of these problems have to do with C/ObjC APIs that might present themselves differently in Swift 3 and Swift 4, using the "API notes" feature in our downstream branch of Clang, and a good subset of these problems have to do with types getting renamed. (This includes being "renamed" into a member, such as NSNotificationName becoming (NS)Notification.Name in Swift.)

What's the problem? Well, there are a few. First of all, an API defined in terms of the Swift 3 name should still be callable in Swift 4. As an example, let's pretend NSNotification.Name was going to be renamed NSNotification.Identifier in Swift 4.

// Swift 3 library
public func postTestNotification(named name: NSNotification.Name) { … }

// Swift 4 app
let id: Notification.Identifier = …
postTestNotification(named: id) // should work

This means the reference to "NSNotification.Name" in the library's swiftmodule needs to still be resolvable. This isn't too bad if we leave behind a typealias for 'NSNotification.Name'. I have a reasonable (but too broad) implementation at https://github.com/apple/swift/pull/8737.

That just leads us to another problem, though: because Swift functions can be overloaded, the symbol name includes the type, and the type has changed. The Swift 3 library exposes a symbol '_T03Lib20postTestNotificationySo14NSNotificationC4NameV5named_tF', but the Swift 4 client expects '_T03Lib20postTestNotificationySo14NSNotificationC10IdentifierV5named_tF'.

My planned approach to combat this was to use the C name of the type in the mangling, producing '_T03Lib20postTestNotificationySo18NSNotificationNamea5named_tF'. This is prototyped in https://github.com/apple/swift/pull/8871.

At this point Slava pointed out I was chasing down a lot of issues when there's a much simpler solution for Swift 4: when importing types, always use the Swift 4 name, and use typealiases to handle Swift 3 compatibility. This defines both of the previous issues away, as well as any more that I just haven't thought of yet.

There are some downsides:
- We currently keep people from using Swift 4 names in Swift 3 code, and we wouldn't be able to do that, since the actual declaration of the type always needs to be available.
- We'd probably want to tweak the "aka" printing in diagnostics to not look through these typealiases. That's not hard, though.
- We can't keep doing this once we have ABI stability. Hopefully framework owners aren't going to continue changing Swift names of types, but we'll probably need to implement my "C name in the mangling" plan anyway, just in case.

What do people think?

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


(Jordan Rose) #6

I suspect we'll end up doing my appended follow-up for this: "mangle me as if my name were ___". That doesn't cover everything the importer does, though (turning enums into structs, swift_wrapper, import-as-member, etc).

I also hope we just don't have to deal with name changes very often in Swift-land.

Jordan

···

On Apr 20, 2017, at 18:25, Michael Ilseman <milseman@apple.com> wrote:

On Apr 20, 2017, at 4:55 PM, Jordan Rose via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

TLDR: Should we just always import C/ObjC types under their Swift 4 names, and use typealiases in Swift 3 mode?

---

Hi, swift-dev. As my recent PRs have probably indicated, I've been working on the problems that can come up when mixing Swift 3 and Swift 4 code. Most of these problems have to do with C/ObjC APIs that might present themselves differently in Swift 3 and Swift 4, using the "API notes" feature in our downstream branch of Clang, and a good subset of these problems have to do with types getting renamed. (This includes being "renamed" into a member, such as NSNotificationName becoming (NS)Notification.Name in Swift.)

What's the problem? Well, there are a few. First of all, an API defined in terms of the Swift 3 name should still be callable in Swift 4. As an example, let's pretend NSNotification.Name was going to be renamed NSNotification.Identifier in Swift 4.

// Swift 3 library
public func postTestNotification(named name: NSNotification.Name) { … }

// Swift 4 app
let id: Notification.Identifier = …
postTestNotification(named: id) // should work

This means the reference to "NSNotification.Name" in the library's swiftmodule needs to still be resolvable. This isn't too bad if we leave behind a typealias for 'NSNotification.Name'. I have a reasonable (but too broad) implementation at https://github.com/apple/swift/pull/8737.

That just leads us to another problem, though: because Swift functions can be overloaded, the symbol name includes the type, and the type has changed. The Swift 3 library exposes a symbol '_T03Lib20postTestNotificationySo14NSNotificationC4NameV5named_tF', but the Swift 4 client expects '_T03Lib20postTestNotificationySo14NSNotificationC10IdentifierV5named_tF'.

My planned approach to combat this was to use the C name of the type in the mangling, producing '_T03Lib20postTestNotificationySo18NSNotificationNamea5named_tF'. This is prototyped in https://github.com/apple/swift/pull/8871.

At this point Slava pointed out I was chasing down a lot of issues when there's a much simpler solution for Swift 4: when importing types, always use the Swift 4 name, and use typealiases to handle Swift 3 compatibility. This defines both of the previous issues away, as well as any more that I just haven't thought of yet.

There are some downsides:
- We currently keep people from using Swift 4 names in Swift 3 code, and we wouldn't be able to do that, since the actual declaration of the type always needs to be available.

I don’t know if this is an important distinction to worry about. That code will still be able to use features from Swift 4, and perhaps even Swift 4 only types (e.g. Substring from SE-0163).

- We'd probably want to tweak the "aka" printing in diagnostics to not look through these typealiases. That's not hard, though.
- We can't keep doing this once we have ABI stability. Hopefully framework owners aren't going to continue changing Swift names of types, but we'll probably need to implement my "C name in the mangling" plan anyway, just in case.

Would this fall under the realm of library evolution, wherein name changes should be versioned? In that case, would we need both symbols whether they came from C or not?


(Michael Ilseman) #7

That seems fair. Imported names are much more likely to experience name churn for prettier APIs, and I’d hate to burden the solution for library evolution with this frequent case. I was hoping it could fall out from whatever the general solution was for library evolution.

···

On Apr 21, 2017, at 10:55 AM, Jordan Rose <jordan_rose@apple.com> wrote:

On Apr 20, 2017, at 18:25, Michael Ilseman <milseman@apple.com <mailto:milseman@apple.com>> wrote:

On Apr 20, 2017, at 4:55 PM, Jordan Rose via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

TLDR: Should we just always import C/ObjC types under their Swift 4 names, and use typealiases in Swift 3 mode?

---

Hi, swift-dev. As my recent PRs have probably indicated, I've been working on the problems that can come up when mixing Swift 3 and Swift 4 code. Most of these problems have to do with C/ObjC APIs that might present themselves differently in Swift 3 and Swift 4, using the "API notes" feature in our downstream branch of Clang, and a good subset of these problems have to do with types getting renamed. (This includes being "renamed" into a member, such as NSNotificationName becoming (NS)Notification.Name in Swift.)

What's the problem? Well, there are a few. First of all, an API defined in terms of the Swift 3 name should still be callable in Swift 4. As an example, let's pretend NSNotification.Name was going to be renamed NSNotification.Identifier in Swift 4.

// Swift 3 library
public func postTestNotification(named name: NSNotification.Name) { … }

// Swift 4 app
let id: Notification.Identifier = …
postTestNotification(named: id) // should work

This means the reference to "NSNotification.Name" in the library's swiftmodule needs to still be resolvable. This isn't too bad if we leave behind a typealias for 'NSNotification.Name'. I have a reasonable (but too broad) implementation at https://github.com/apple/swift/pull/8737.

That just leads us to another problem, though: because Swift functions can be overloaded, the symbol name includes the type, and the type has changed. The Swift 3 library exposes a symbol '_T03Lib20postTestNotificationySo14NSNotificationC4NameV5named_tF', but the Swift 4 client expects '_T03Lib20postTestNotificationySo14NSNotificationC10IdentifierV5named_tF'.

My planned approach to combat this was to use the C name of the type in the mangling, producing '_T03Lib20postTestNotificationySo18NSNotificationNamea5named_tF'. This is prototyped in https://github.com/apple/swift/pull/8871.

At this point Slava pointed out I was chasing down a lot of issues when there's a much simpler solution for Swift 4: when importing types, always use the Swift 4 name, and use typealiases to handle Swift 3 compatibility. This defines both of the previous issues away, as well as any more that I just haven't thought of yet.

There are some downsides:
- We currently keep people from using Swift 4 names in Swift 3 code, and we wouldn't be able to do that, since the actual declaration of the type always needs to be available.

I don’t know if this is an important distinction to worry about. That code will still be able to use features from Swift 4, and perhaps even Swift 4 only types (e.g. Substring from SE-0163).

- We'd probably want to tweak the "aka" printing in diagnostics to not look through these typealiases. That's not hard, though.
- We can't keep doing this once we have ABI stability. Hopefully framework owners aren't going to continue changing Swift names of types, but we'll probably need to implement my "C name in the mangling" plan anyway, just in case.

Would this fall under the realm of library evolution, wherein name changes should be versioned? In that case, would we need both symbols whether they came from C or not?

I suspect we'll end up doing my appended follow-up for this: "mangle me as if my name were ___". That doesn't cover everything the importer does, though (turning enums into structs, swift_wrapper, import-as-member, etc).

I also hope we just don't have to deal with name changes very often in Swift-land.

Jordan