waj
waj

Reputation: 1185

"some Protocol" causes type to not conform to protocol

I don't understand why this doesn't compile. It does if I remove the where restriction from the P type.

import Combine

protocol Foo {
    associatedtype P: Publisher where P.Output == Int
    var publisher: P { get }
}

struct Bar: Foo {
    var publisher: some Publisher {
        Just(1)
    }
}

The error says that Type 'Bar' does not conform to protocol 'Foo'. I guess it's because publisher return type is not just any some Publisher. But in SwiftUI, the View uses a similar approach, just that it doesn't have restrictions over the View type.

Is there any way I can make this code to compile?

Upvotes: 2

Views: 1072

Answers (1)

Sweeper
Sweeper

Reputation: 271050

The reason why it doesn't compile is because some Publisher declares an opaque type, but the protocol requires that the type must be "see-through".

some Publisher is "opaque" in the sense that callers cannot see exactly what type the property actually is, and can only know that it conforms to Publisher. This directly contradicts with the protocol requirement that P.Output has to be Int. To check P.Output is Int, you have to "see through" some Publisher, but you can't.

Since the compiler can't check the publisher's Output, it can't check whether your type really conforms to the protocol or not. Therefore it chooses the "safe route" concludes that your type does not conform to the protocol.

I think you should use the AnyPublisher type eraser:

var publisher: AnyPublisher<Int, Never> {
    Just(1).eraseToAnyPublisher()
}

SwiftUI's View protocol does not have this problem because it does not require Body to be "see-through". It just requires that Body is a conformer of View, which some View, by definition, is.

Upvotes: 3

Related Questions