I like this direction, but you can't constrain typealiases in this way:
protocol P1 { associatedtype Unevaluated }
protocol P2 { associatedtype Unevaluated }
typealias P3 = P1 & P2 where P1.Unevaluated == P2.Unevaluated
// => error: 'where' clause cannot be attached to a non-generic declaration
// typealias P3 = P1 & P2 where P1.Unevaluated == P2.Unevaluated
// ^
You would also need specific instantiations of P1
and P2
(Encodable
and Decodable
) whose associated types are given concrete values.
This is possible:
struct _Unevaluated {}
protocol P1 {
typealias Unevaluated = _Unevaluated
}
protocol P2 {
typealias Unevaluated = _Unevaluated
}
typealias P3 = P1 & P2
print(P3.Unevaluated.self) // => _Unevaluated
but works in a surprising way. P3 actually shows two different overloads for Unevaluated
; they just happen to both be the same. You can actually do this:
struct _Unevaluated1 {}
struct _Unevaluated2 {}
protocol P1 {
typealias Unevaluated = _Unevaluated1
}
protocol P2 {
typealias Unevaluated = _Unevaluated2
}
typealias P3 = P1 & P2
print(P3.Unevaluated.self) // => _Unevaluated2
I'm not sure how Swift chooses which one "wins", but this appears to return _Unevaluated2
regardless of whether you write P1 & P2
or P2 & P1
(it's possible the composition is always sorted and the last definition wins out; I'm just surprised there are no warnings or anything). That's neither here nor there though.
Seems like we can expand the protocols to contain this (and can potentially include a matching _
'd type as the actual underlying type for the protocols). @jrose How does adding typealias
es to protocols interact with the ABI?