|
| 1 | +--- |
| 2 | +date: 2024-09-24 |
| 3 | +title: Swift 6's New @retroactive Attribute |
| 4 | +slug: swift-6-retroactive-attribute |
| 5 | +images: [""] |
| 6 | +description: Learn about retroactive protocol conformance, and why you probably shouldn't use it on external types. |
| 7 | +topics: [Swift] |
| 8 | +--- |
| 9 | + |
| 10 | +# Swift 6's New `@retroactive` Attribute |
| 11 | + |
| 12 | +Swift 6.0 introduced the `@retroactive` attribute to address a specific issue with protocol conformances. Here's what you need to know: |
| 13 | + |
| 14 | +## The Problem |
| 15 | + |
| 16 | +Suppose you are using a type from an external library and realize that the type does not conform to a protocol such as `Codable`. You might be tempted to add your own conformance. |
| 17 | + |
| 18 | +```swift |
| 19 | +import ExternalLibrary |
| 20 | +extension ExternalType: Codable { |
| 21 | + // implementation here |
| 22 | +} |
| 23 | +``` |
| 24 | + |
| 25 | +However, doing this can be quite problematic. What happens if the library owner later adds their own conformance? Which code will execute? Your conformance or their conformance? The answer is that the behavior will be undefined at runtime, since we don't know which conformance will "win". Even worse, this same problem will propagate to every library that imports your library.[^1] |
| 26 | + |
| 27 | +[^1]: There are a few exceptions to the this which you can find [here](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0364-retroactive-conformance-warning.md#detailed-design) and [here](https://forums.swift.org/t/amendment-se-0364-allow-same-package-conformances/71877). |
| 28 | + |
| 29 | +## The Solution: `@retroactive` |
| 30 | + |
| 31 | +To combat this problem, Swift 6.0 now emits a warning any time you retroactively add a conformance to an external type. However, there are some scenarios where it might be best to extend external types, despite this risk. |
| 32 | + |
| 33 | +So, the `@retroactive` attribute allows you to explicitly declare that you are intentionally adding a conformance that might conflict with future updates to the original module. |
| 34 | + |
| 35 | +## When to Use It |
| 36 | +**⚠️ You probably shouldn't use `@retroactive`.** |
| 37 | +Consider it a code smell. |
| 38 | + |
| 39 | +If you **must** use it, then be sure to check every time you update your dependency to a new version. If they have added the conformance themselves, then this will create a conflict. |
| 40 | + |
| 41 | +If you use `@retroactive`, you are, in fact, explicitly declaring that you acknowledge the risk and are willing to take responsibility for potential future conflicts. |
| 42 | + |
| 43 | +## How to Use It |
| 44 | + |
| 45 | +```swift |
| 46 | +extension ExternalType: @retroactive ExternalProtocol { |
| 47 | + // Implementation here |
| 48 | +} |
| 49 | +``` |
| 50 | + |
| 51 | + |
| 52 | +## Alternative (for pre-Swift 6) |
| 53 | + |
| 54 | +If you need to support older Swift language modes, you can silence the warning by fully qualifying the types: |
| 55 | + |
| 56 | +```swift |
| 57 | +extension Module.ExternalType: OtherModule.ExternalProtocol { |
| 58 | + // Implementation here |
| 59 | +} |
| 60 | +``` |
| 61 | + |
| 62 | +## Conclusion |
| 63 | +Remember, while `@retroactive` provides a solution, it's best to avoid adding conformances to external types and protocols whenever possible to maintain better compatibility and reduce potential conflicts. |
| 64 | + |
| 65 | + |
| 66 | +## Recommended Reading |
| 67 | +- Read the full Swift Evolution proposal for more [info](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0364-retroactive-conformance-warning.md). |
| 68 | +- [Extensions in Swift: How and when to use them - SwiftLee](https://www.avanderlee.com/swift/extensions/) |
0 commit comments