Why do we prohibit redundant declarations of conformance to a protocol?

I was just experimenting with some ideas relating to serialization and I got blocked by a compilation error that doesn't seem necessary.

Here's the upshot:

typealias Foo = Codable & ProtocolA & ProtocolB
typealias Bar = Codable & ProtocolC & ProtocolD

struct Baz: Foo, Bar { // Redundant conformance of 'Baz' to protocol 'Decodable'

}

I found this related post with this comment:

which I think indicates that duplicates should be permitted (but as I'm describing, that doesn't seem to be true).

Is there a good reason that we don't allow redundant declarations of protocol conformance?

7 Likes

Are you speaking exclusively about redundancy to the right of the colon, or would you expect to be able to declare two separate conformances to Foo and Bar?

OTOH this is fine:

protocol ProtocolA {}
protocol ProtocolB {}
protocol ProtocolC {}
protocol ProtocolD {}

protocol Foo: Codable, ProtocolA, ProtocolB {}
protocol Bar: Codable, ProtocolC, ProtocolD {}

struct Baz: Foo, Bar {} // ✅

Whether this disparity is a bug or a feature I don't know.

2 Likes

I wondering why we can’t redundantly declare the conformance. The fact that we can’t redundantly implement the conformance is no mystery to me.

FYI Slava recently pointed this out on the noncopyable generics thread.

1 Like

It’s not a bug or a feature, it’s two different code paths. The inheritance clause of a protocol is a shortcut for a series of Self: Foo requirements so redundancy is just ignored there. We could do the same for concrete types, I think the potential confusion from someone declaring a duplicate entry is low.

6 Likes

If this disparity is intentional - that's a feature, otherwise that's a bug, I can't see how it could be anything else. Could be the case that whoever implemented it didn't have the prescribed intended behaviour to match, and whatever we have now could be retroactively called the intended behaviour, in which case the current behaviour is "a feature".

Sure, but that requires a decision about what the "intended behavior" actually is, which isn't always obvious/trivial.

Are there any specific complications that you foresee if we allow the same protocol to appear twice in a conformance declaration?

Not that I see, no. Given that we allow this to be expressed in a where clause without issue it seems fine to me to allow it directly in the inheritance clause (particularly when it's incidental by way of two typealiases; IMO that the specific code in your example at top-of-thread gets diagnosed leans toward bug).

3 Likes

I think there is an important difference between:

typealias A = P
typealias B = P

struct S: A, B {}

…and:

struct S: P, P {}

The latter probably is an error, because even though it's technically harmless it could mean the user meant to write "P2" for one of the conformances, or somesuch. There's also no good reason (that I can think of) for that syntax (I consider clumsy code generators not a good reason). It'd be wise to warn about it.

But for the former, those declarations can be spread widely apart within the code, might be complicated by the typealiases including - now, in the past, or in the future - other protocols as well, etc. It's simply less likely that it's an error. Conceptually A and B might be different things even if in practice they overlap or are even identical. And maybe they're not always identical, but it depends on some #ifs or somesuch, or they weren't identical in the past but became so but can't be removed or consolidated for backwards compatibility reasons, etc.

i.e. the compiler should really only be looking at the input text for this diagnostic, not caring about the semantics. Just checking for the same words in a single protocol list (whether that be ,-separated or &-separated).

11 Likes

I can get on board with this, except that I would add that I also think the diagnostic for when the same protocol is explicitly written twice should be downgraded to a warning.

2 Likes

Agreed. I think this should probably just be a warning