I have recently come across an interesting discussion on protocols in which @Nickolas_Pohilets uses the phrase lookup in the conformance tables. Then, @Andropov proposes an elegant counter example.
After reading that discussion, I thought it would be useful to have a central repository-like index of interesting discussions on protocols.
So here is my list, which I intend to grow as I encounter new ones.
Make Default Implementations Safer
Covariant Self on Protocols and Classes
Why Is Covariant Self more flexible on protocols than classes?
Summary
Lightweight Same-Type Requirements for Primary Associated Types
SE-0346: Lightweight same-type requirements for primary associated types
Infinitely Recursive Associated Types
Limitations with infinitely-recursive associated types
Summary
Protocol Where Clause vs Protocol Inheritance
Associated Type Inference
Recent improvements to associated type inference
Summary
Synchronous Functions Can Satisfy Async Protocol Requirements
Protocol with async function allows implementation without async?
See Also SE-0296 - Protocol conformance
A protocol requirement can be declared as async. Such a requirement can be satisfied by an async or synchronous function. However, a synchronous function requirement cannot be satisfied by an async function. For example:
Summary
protocol Asynchronous { func f() async } protocol Synchronous { func g() } struct S1: Asynchronous { func f() async { } // okay, exactly matches } struct S2: Asynchronous { func f() { } // okay, synchronous function satisfying async requirement } struct S3: Synchronous { func g() { } // okay, exactly matches } struct S4: Synchronous { func g() async { } // error: cannot satisfy synchronous requirement with an async function }
This behavior follows the subtyping/implicit conversion rule for asynchronous functions, as is precedented by the behavior of throws.
Why Isn't My Implementation Called?
Summary
The following fact may help to refine your understanding of how Swift handles default arguments—
Given the following function
f
in library A and a user that calls the function in app B:// library A public func f(x: Int = 42) { ... } // app B f()
A lot of folks mistakenly think that this would compile as though it were written like this:
// library A public func f(x: Int) { ... } public func f() { f(x: 42) } // app B f()
Not so. In fact, it compiles as though it were written like this:
// library A public func f(x: Int) { ... } // app B f(x: 42)
In other words, the default value is emitted into the caller (here, app B).
Cases Where Non-Exact Matches Are Accepted
Summary
It should be noted that there are some cases where non-exact matches are accepted by the compiler. For example:
protocol P { func f() async throws } struct S: P { func f() {} // f matches P’s requirement even though it’s not asynchronous nor throwing }
Summary
The other situation you might call an "inexact match" is when the witness is more generic than the requirement. The specific condition where it works if there's a fixed set of concrete substitutions that can apply to the witness to make it satisfy the signature of the requirement. For example:
protocol P { func f1(_: Int) func f2<T: Equatable>(_: T) } struct S: P { func f1<T>(_: T) {} // T is always Int func f2<T>(_: T) {} // T happens to be Equatable but it's not needed }
The reason that we don't allow arbitrary function subtype conversions is that associated type inference relies on exact matching. Subtype conversions would introduce ambiguity that requires new forms of reasoning to sort out:
protocol P { associatedtype A func f() -> A func g() -> A } struct S: P { // this is the most specific type that works for both: // typealias A = NSObject? func f() -> NSString? {} func g() -> NSObject {} }
Why Can't any FixedWidthInteger Conform to FixedWidthInteger?
Summary
To be clear, in the general case, this isn't even how the language works—it's just how logic works.
For example, every type that conforms to
FixedWidthInteger
is a fixed-width integer. Meanwhile,any FixedWidthInteger
must be able to hold a value of any conforming type (for example, anInt32
or anInt64
). This means thatany FixedWidthInteger
is not a fixed-width integer. Therefore, it cannot conform toFixedWidthInteger
.