-1

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.

AnderCover
  • 2,488
  • 3
  • 23
  • 42
  • This is how Swift works currently, it distinguishes a type itself (any generic Something) and a box, containing the type (the Something itself). At WWDC22 they promised us, it's not going to be a problem anymore after Swift 5.7: https://developer.apple.com/videos/play/wwdc2022/110354/ – lazarevzubov Jul 17 '22 at 06:24
  • @lazarevzubov But I'm actually currently using Swift 5.7 right now (with Xcode 14 Beta 3) –  Jul 17 '22 at 06:29

1 Answers1

0

Try declaring your ProviderView with any Provider

struct ProviderView: View {
    let provider: any Provider
    
    var body: some View {
        Text(provider.get())
    }
}
AnderCover
  • 2,488
  • 3
  • 23
  • 42