I don't think we can replace both P.Type
and P.Protocol
with (any P).Type
, because there is fundamental different between the two - P.Type
allows to call static protocol methods, while P.Protocol
does not.
protocol P {
static func generate() -> Self
}
extension Int: P {
static func generate() -> Int { 42 }
}
let t1: (any P).Type = (any P).self
t1.generate() // error
let t2: P.Type = Int.self
t2.generate() // ok
So, (any P).Type
is good as replacement for P.Protocol
, but P.Type
needs to stay, unless we adopt generalised syntax any<T> T.Type where T: P
. But even with generalised syntax, IMO, that's a common case that deserves a convenience spelling, so I guess P.Type
is here to stay.
When any
keyword becomes mandatory P.self
is no longer a valid syntax, only (any P).self
. I think already with optional any
keyword, P.self
should produce a warning with a fix-it to turn it into (any P).self
.
It is compelling to add subtyping relationship between P.Type
and (any P).Type
- but there are gotchas with self-conforming existentials - see Why there is no subtyping relation between existential meta types?.
I think, it is possible to avoid self-conforming existentials using universal hashability and existential subtyping/convertibility as a constraint.
For example, we would not need self-conformance for Error
if everywhere conformance to Error
is replaced with convertible to (any Error)
constraint.
protocol MyError: Error {
var myStatusCode: Int { get }
}
enum FooError: MyError { ... }
enum BarError: MyError { ... }
enum OldResult<Success, Failure> where Failure : Error { ... }
enum NewResult<Success, Failure> where Failure : (any Error) { ... }
OldResult<Void, any Error> // only works with self-conformance
OldResult<Void, any MyError> // does not work even with self-conformance
OldResult<Void, FooError> // works
NewResult<Void, any Error> // works
NewResult<Void, any MyError> // works
NewResult<Void, FooError> // works