Skip to content

Xcode 16 Retroactive Conformance Warning

When migrating projects to Xcode 16, you might encounter this new warning:

Extension declares a conformance of imported type 'Date' to imported protocol 'Identifiable'; this will not behave correctly if the owners of 'Foundation' introduce this conformance in the future

This occurs when declaring protocol conformances for types outside your control—such as extending Apple’s Date to adopt Identifiable:

swift
extension Date: Identifiable {
    public var id: TimeInterval { timeIntervalSince1970 } // Warning triggers here
}

The warning surfaces for many common protocols like CustomStringConvertible, Equatable, Hashable, and Sendable.

Why This Matters

This warning (implemented through Swift Evolution SE-0364) protects against ambiguous behavior when:

  1. Module owners add the conformance later: The compiler won't know whether to use your implementation or the module's official version.
  2. Multiple conflicting conformances exist: If both your code and the original module declare conformance to the same protocol, runtime behavior becomes unpredictable.

1. Wrap External Types

Create a custom wrapper for the type instead of extending it directly. This avoids protocol conflicts entirely and gives you full control:

swift
struct SafeDate: Identifiable {
    let rawValue: Date
    var id: TimeInterval { rawValue.timeIntervalSince1970 }
}

When to use: For non-Sendable protocols in shared code. Ideal when you need control over conformance logic.

2. Use @retroactive Attribute (Xcode 16+)

Acknowledge the risk explicitly by marking the conformance as retroactive:

swift
extension Date: @retroactive Identifiable {
    public var id: TimeInterval { timeIntervalSince1970 }
}

When to use: When you're aware of the risks and need original-type conformance. Wrap in a compiler check to maintain compatibility with older Xcode versions:

swift
#if hasFeature(RetroactiveAttribute)
extension Date: @retroactive Identifiable {
    public var id: TimeInterval { timeIntervalSince1970 }
}
#endif

3. Fully Qualify Module Names

Work across Xcode versions by explicitly declaring module origins:

swift
extension Foundation.Date: Swift.Identifiable {
    public var id: TimeInterval { timeIntervalSince1970 }
}

When to use: When @retroactive isn't viable, and you need backwards compatibility.

4. Restructure Context-Specific Conformances

For demo/test targets: If a conformance only exists in sandboxed code (like an Example app), move both the protocol and conformance there instead of a shared module:

swift
// Define within ExampleApp target
protocol DemoIdentifiable: Identifiable {}
extension Date: DemoIdentifiable { /* ... */ }

For libraries: Submit conformance requests to the original module owner (optimal but slow).


Key Recommendations

  • Avoid unqualified extensions for public types in production shared modules.
  • Use type wrappers for maximum stability.
  • Reserve @retroactive/qualified names for cases where wrappers cause significant overhead.
  • Audit existing extensions—many trivial conformances (like Hashable for basic types) might already exist in current SDKs.

Maintenance Tip

Always specify public access explicitly in extensions to avoid default internal visibility surprises—especially in mixed-module projects.

By proactively structuring conformances, you maintain predictable behavior while silencing Xcode's warnings about protocol collisions.