Why is (any Any).Type
different to any Any.Type
That's it. That's the post.
for any concrete T.Type
, it can be upcast to any Any.Type
(any Any).Type
can be implicitly opened to some concrete T.Type
Why the assymmetry?
Is it possible to convert from one to the other (and back again)?
1 Like
any Any.Type
is an existential container which can store any concrete metatype. You can also spell it as Any.Type
.
(any Any).Type
is specifically the type of the Any
type.
Int.Type
is a subtype of any Any.Type
. However, Int.Type
is not a subtype of (any Any).Type
.
4 Likes
Thanks.
So prior to the introduction of the any
keyword, there was no way to spell "the type of the Any
type"?
And why the assymmetry? Like, if I have:
protocol P {}
struct S: P {}
I expect that I can both upcast an instance of S
to any P
, and open an existential of type any P
back to a generic of type S
.
But when .Type
gets involved, I can upcast String.self
(of type String.Type
) to any Any.Type
, but I can't open any Any.Type
back to a generic of type String.Type
. I can open (any Any).Type
back to a generic of type String.Type
, though. If I knew how to get an (any Any).Type
representing String.self
?
xwu
(Xiaodi Wu)
December 17, 2022, 6:06am
4
The "protocol metatype" of Any
, or the singleton metatype of the existential type Any
, was (and still can be) spelled Any.Protocol
, but is additionally now spelled (any Any).Type
.
The "existential metatype" which used to be spelled Any.Type
can now also be spelled any Any.Type
, but just as for Any
the new keyword is considered optional for the existential metatype.
xwu
(Xiaodi Wu)
December 17, 2022, 6:25am
5
OneSadCookie:
I expect that I can both upcast an instance of S
to any P
, and open an existential of type any P
back to a generic of type S
.
But when .Type
gets involved
...existential opening also works with metatypes:
protocol P { }
struct S: P { }
func h<T: P>(_ x: T.Type) {
print(x)
}
h(S.self) // prints "S"
func i(_ x: any P.Type) {
h(x)
}
i(S.self) // prints "S"
Yeah, I can't explain why existential opening specifically doesn't work currently when it comes to Any.Type
(and also AnyObject.Type
):
func j<T>(_ x: T.Type) {
print(x)
}
j(S.self)
func k(_ x: Any.Type) {
j(x)
// error: cannot convert value of type 'any Any.Type' to
// expected argument type 'T.Type'
}
k(S.self)
Seems like a bug? cc @hborla
(At a minimum, the diagnostics that arise here are hilariously off-base, which is itself a bug.)
1 Like
xwu:
The "protocol metatype" of Any
, or the singleton metatype of the existential type Any
, was (and still can be) spelled Any.Protocol
, but is additionally now spelled (any Any).Type
.
is (any P).Type
equivalent to P.Protocol
for any protocol P
?
Yeah, P.Protocol
is the older syntax.
3 Likes
Was there any follow-up on this? It seems like openExistential( :do:) is the only option now, but that's supposedly not the idea.
Here is an example I have to check if a UIViewController conforms to some protocol:
extension UIViewController {
nonisolated func conforms(to protocolType: Any.Type) -> Bool {
func check<T>(type: T.Type) -> Bool {
return (self is T)
}
return _openExistential(protocolType, do: check(type:))
}
}
I would like to avoid using openExistential( :do:), but can't (even in the current Swift 5.7, right?)
1 Like
You should be able to just call check(protocolType)
— Swift 5.7 has implicit opening of existentials.
Alejandro
(Alejandro Alonso)
March 26, 2023, 5:44pm
10
I believe implicit opening of Any.Type
is disabled until Swift 6 iirc.
1 Like
I perused threads when this kind of syntax was being discussed. Are the results documented somewhere? I don't know how to write all the things now.
Is there shorthand syntax coming for metatypes that will match the look of any P.type
…
struct S: P { }
protocol P { }
func ƒ(_ source: any P.Type) { }
…but deal with a concrete metatype instead?
func ƒ<T: P>(_ source: T.Type) { }
func ƒ(_ source: some P.Type) { } // doesn't compile
Is there some way to refer to an "existential container which can store any concrete metatype", when the container is not Any
?
S.self is Any // true
S.self is P // false
I perused threads when this kind of syntax was being discussed. Are the results documented somewhere? I don't know how to write all the things now.
Is there shorthand syntax coming for metatypes that will match the look of any P.type
…
struct S: P { }
protocol P { }
func ƒ(_ source: any P.Type) { }
…but deal with a concrete metatype instead?
func ƒ<T: P>(_ source: T.Type) { }
func ƒ(_ source: some P.Type) { } // doesn't compile
Edit: Maybe it's (some P).Type? I have to think about the parens differences here.
Is there some way to refer to an "existential container which can store any concrete metatype", when the container is not Any
?
S.self is Any // true
S.self is P // false
(I'm still looking for a way to replicate the old behavior .)
Unfortunately I am getting the error:
"Cannot convert value of type 'any Any.Type' to expected argument type 'T.Type'"