This isn't quite it — the full issue is clarified a little by looking at the notes the compiler provides:
error: type 'User' does not conform to protocol 'Constructible'
class User: ConstructibleFromJSON, ConstructibleFromProtobuffer {
^
note: ambiguous inference of associated type 'RepresentativeData': 'JSON' vs. 'ProtoBuff'
associatedtype RepresentativeData
^
note: matching requirement 'init(_:)' to this declaration inferred associated type to 'JSON'
required init? (_ data: JSON) { return nil }
^
note: matching requirement 'init(_:)' to this declaration inferred associated type to 'ProtoBuff'
required init? (_ data: ProtoBuff) { return nil }
^
Your Constructible
protocol has an associatedtype
requirement which conforming types must satisfy; the compiler is trying to infer the type of RepresentativeData
but can't because the conformances of ConstructibleFromJSON
and ConstructibleFromProtobuffer
have the same associatedtype
requirement and it can't choose a type for you which would satisfy those constraints. To make this valid, you need to provide an explicit typealias RepresentativeData
to express what you mean.
Decoder
doesn't have this problem because it doesn't have associatedtype
requirements.
Note also that the code you have likely doesn't quite represent what you mean. Your ConstructibleFromJSON
and ConstructibleFromProtobuffer
have initialization requirements that specify an init?(_:)
, but don't actually require that those initializers be acting on RepresentativeData
. Although type inference works out so that if you have a type which conforms to either ConstructibleFromJSON
or ConstructibleFromProtobuffer
, providing an init?(_:)
will likely meet the requirements of the protocol and allow for the right inference, the following is equally valid at the moment:
protocol ConstructibleFromProtobuffer: Constructible {
init?(_ data: ProtoBuff) // does not require RepresentableData == ProtoBuff
func foo()
}
extension ConstructibleFromProtobuffer {
func foo() {
print(Self.RepresentativeData.self)
}
}
struct Foo: ConstructibleFromProtobuffer {
typealias RepresentativeData = JSON
init?(_ data: ProtoBuff) {} // meets the ConstructibleFromProtobuffer requirement
}
Foo(ProtoBuff())?.foo() // JSON
So for now, you can totally write
class User: ConstructibleFromJSON, ConstructibleFromProtobuffer {
typealias RepresentativeData = JSON
init?(_ data: JSON) {}
init?(_ data: ProtoBuff) {}
}
and fulfill all protocol requirements since you have a RepresentativeData
type and meet the init?(_:)
requirements.
To constrain the protocols to likely mean what you want, you'd have to write
protocol ConstructibleFromJSON: Constructible where RepresentativeData == JSON {
// ...
}
protocol ConstructibleFromProtobuffer: Constructible where RepresentativeData == ProtoBuff {
// ...
}
Then you'd get
error: 'ConstructibleFromProtobuffer' requires the types 'User.RepresentativeData' (aka 'JSON') and 'ProtoBuff' be equivalent
struct User: ConstructibleFromJSON, ConstructibleFromProtobuffer {
^
note: requirement specified as 'Self.RepresentativeData' == 'ProtoBuff' [with Self = User]
struct User: ConstructibleFromJSON, ConstructibleFromProtobuffer {
^