Swift 5.6: using opaque type with protocols and associate types

Viewed 85

I'm trying to use the 'some' keyword with protocols and associate types as shown hereafter (Swift 5.6).

protocol Foo {
    associatedtype yep
    func yo(_ a:yep)
}

struct A: Foo {
    func yo(_ a:String) {
        print(a)
    }
}

var a: some Foo = A()
a.yo("hello")

Unfortunately, I get the following error message regarding the last line:

enter image description here

I don't understand why the argument in the yo function should be the protocol's one (yep) instead of the struct's (String). ‍ (my approach should be refined ?)

Thanks in advance for your expert advice to find out the solution.

2 Answers

I think you are misunderstanding what some means. It's purpose is to

the return type is chosen by the callee, and comes back to the caller as abstracted

(source). It's also called a "reverse generics"

So you want to use some when caller should not be in control (and shouldn't eve know) of the concrete type of the variable, and should only know that it conforms to some protocol, while the callee is the one that sets the concrete type (hidden from caller).

In your use case though, if you want to do something like a.yo("hello"), it means the caller wants to say "hey, I will use a specific type String, which means I am using a concrete type A here", and you are abstracting the type from callee. That's a use case for classic generics, not for reverse generics, represented by keyword some.

Having said that, you could combine both:

protocol Foo {
    
    func yo<yep>(_ a:yep)
}

struct A: Foo {
    func yo<String>(_ a: String) {
        print(a)
    }
}

var a: some Foo = A()

a.yo("hello") // works

So what we have here:

  • reverse generics to abstract the specific type A from the caller (using some Foo).
  • and "classical" generics to abstract the specific type String from the callee in a.yo("hello")

Yep is not String unless you say it is—you can do that with a primary associated type.

protocol Foo<yep> {
var a: some Foo<String> = A()
Related