I have a simple protocol Provider
like this:
protocol Provider {
func get() -> String
}
And a struct S
that has an existential Provider
as a field:
struct S {
var provider: any Provider
}
I also have a view ProviderView
like this:
struct ProviderView<P: Provider>: View {
let provider: P
var body: some View {
Text(provider.get())
}
}
And an implementation of Provider
like so:
struct DummyProvider: Provider {
func get() -> String {
"Hello World!"
}
}
Now the problem comes when I try to use ProviderView
passing in S.provider
:
struct ContentView: View {
let s = S(provider: DummyProvider())
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
ProviderView(provider: s.provider) // This is the erroring line.
}
}
}
An error occurs:
Type 'any Provider' cannot conform to 'Provider'
Now this is expected, as described excellently in an answer here, and here.
The reason why this code doesn't work is because the View
's body
property is fixed at runtime, therefore ProviderView
being generic over a dynamic type isn't allowed.
The thing is, a super thin type erasing AnyProvider
struct fixes this issue:
struct AnyProvider: Provider {
let erased: any Provider
func get() -> String {
return erased.get()
}
}
Now ProviderView
has a concrete type to be generic over.
However, you can see that AnyProvider
itself literally just stores an any Provider
member variable. The size of AnyProvider
should still be unknown.
I think if the problem were that the size of any Provider
isn't known at runtime, then why does using AnyProvider
solve this? After all, it just contains a single field which has an unknown size at runtime.
So my question is: Why isn't Swift able to synthesize a similar wrapper? What is the difference between using any Provider
and a struct that contains a single field of type any Provider
?
What prevents Swift from allowing you to use any Provider
vs AnyProvider
?
How is AnyProvider
any more concrete than any Provider
other than its type?
I really would like to know if I'm missing something.
P.S: I'm using Xcode 14 Beta 3 with Swift 5.7.