Why doesn't this protocol conformance work? (covariance?)

I create two protocols:

protocol Payment {
    var productIdentifier: String { get }
    var quantity: Int { get }
}

protocol Transaction {
    var payment: Payment { get }
}

Then I try to make the StoreKit classes conform, like this:

extension SKPayment: Payment {  }  // compiler okay with this
extension SKPaymentTransaction: Transaction {  }  // error here

The compiler wants me to add the var payment: Payment to make SKPaymentTransaction conform to Transaction. But SKPaymentTransaction already has a property called payment. It's an SKPayment, which I've declared is a Payment. It seems like the compiler could accept this. It's logically sound (or am I missing something?).

It would make sense to disallow it, if SKPaymentTransaction.payment were settable.

I think if the compiler understood covariance here it would accept it. (?)

I can't implement it explicitly either, because I can't write:

var payment: Payment {
    return self.payment  // infinite recursion
}

Are you sure this is the design you want, and not eg. an associatedtype for Transaction.Payment?

If you are absolutely certain that the existential is what you want, you could use the unofficial attribute @_implements.

1 Like

Wow, didn't know about @_implements, thanks!

I tried associated types first, but I didn't like how it was then forcing everything to become generic. Now I'm thinking it's a more accurate design and need to try that again. I have a class called StoreHelp that is a facade to in-app purchase stuff. I pass it a parameter that conforms to protocol StoreAPI, which would be either the real app store, or a mock for testing. And that protocol uses the Transaction and Payment protocols from my question. If StoreAPI has associated types for Payment and Transaction, then maybe I need to create some of those manual existential types (AnyStoreAPI) to pass around, so that not everything that touches it has to have generic type args. ?

Terms of Service

Privacy Policy

Cookie Policy