On Xcode14beta5, macOS Ventura 13.0, the following code runs fine:
protocol P { var p: String { get } }
struct S: P { let p="hello world" }
protocol Q {
associatedtype A
func f(a: A)
}
struct R: Q {
typealias A = S
func f(a: S) { print(a.p) }
}
let r = R()
r.f(a: S()) // Output: hello world
Reading SE-0346 section "Other positions", I thought I should be able to use the new constrained protocol syntax with the primary associated type A as in:
protocol Q<A> {
associatedtype A
func f(a: A)
}
struct R: Q<S> {
//typealias A = S
func f(a: S) { print(a.p) }
}
but Xcode gave me the error message, "Cannot inherit from protocol type with generic argument 'Q<S>'" on the struct R: Q<S> line. Am I using the new syntax incorrectly? What's the correct usage? Thanks.
My apologies, this is not currently implemented because the behavior of a constrained protocol type here is slightly different than the other positions; as you guessed, it implies a type alias. We should make it work, so that
struct R: Q<S> {}
is equivalent to the second form with the commented out type alias:
The feature you’re asking for is syntax sugar for declaring a conformance together with a type alias so it doesn’t really permit anything new. The Swift generics model does not permit a concrete type to conform to the same protocol more than once.
protocol P { associatedtype A }
struct S {}
extension S: P { typealias A = Int }
extension S: P { typealias A = String }
func f<T: P>(_: T) { print(T.A.self) }
f(S())
If this were allowed, would this print Int or String?
Sorry, I think I misunderstood your previous message. You were explaining that lifting this limitation wouldn't enable my desired use-case and not that my use-case is syntactic sugar.
But wouldn't this be a prerequisite for a hypothetical dynamic typealias?
protocol P<A> { associatedtype A }
struct S: P { associatedtype A = Double }
extension S: P<Int> // interpreted { typealias P.Int = Int }
extension S: P<String> // interpreted { typealias P.String = String }
This way print would be well defined.
But I think the crucial question is whether a protocol with an associated type should be considered unique.
When a struct S conforms to a protocol P, it may do so in only one way; that is, it may and must only fulfill each requirement exactly once. This includes the associated type requirement A.
Protocols are not generic, and primary associated types are not generic parameters. In fact, one reason we adopted P<A> syntax for a primary associated type A is precisely because we have no plan to support a generic parameter A using the same syntax.