Protocol extensions and inheritance

Under the protocols section in the language guide, it is explained that:

Protocol extensions can add implementations to conforming types but can’t make a protocol extend or inherit from another protocol. Protocol inheritance is always specified in the protocol declaration itself.

I was wondering why that is (see my emphasis). Although only a beginner, the idea of extending protocols to make them conform to other protocols seems very intuitive to me, and I would expect it to follow the behavior of types where it is allowed.

Eg, it is not directly clear to me what I should do when I don't have access to the declaration of the protocol A, but would like for all types that conform to it to also inherit conformance to another protocol B.

I'm sure I'm missing something. Looking forward to learning more!

1 Like

Because if some module declares a protocol A and then you would extend it to also inherit from a protocol B, then suddenly all the types conforming to A in the original module would need to conform to B as well — but, of course, they can't automatically do that.

What you can do for your own types instead is to declare a protocol composition like

typealias MyProtocol = A & B

and conform your types to this composition.

Wouldn't using an extension to provide default implementation solve this caveat?

This still doesn't quite solve the problem I described, ie getting all types (not necessarily mine) that already conform to A, to also conform to B (by providing default implementation).

Here's a short example that I hope will help illustrate my point of confusion.

Let's say we have

protocol A {
    var name: String { get }
}
extension A {
    var name: String {
        "Deafult name"
    }
}
struct Foo: A {}
struct Bar: A {}

And now we wish for all types that conform to A (ie Foo and Bar) to also conform to CustomStringConvertible with default implementation. What I intuitively would try is

extension A: CustomStringConvertible {
    var description: String {
        name
    }
}
// Gives error: Extension of protocol 'A' cannot have an inheritance clause

However, that doesn't work. My question is

  1. why (what's the reasoning behind this), and
  2. how would I write this in correct, idiomatic swift?

Thanks for having a look!

There is no theoretical reason why it can't be done (although there may be constraints in terms of what can be implemented without breaking ABI); it simply hasn't been implemented. That said, to implement such a feature would be a very large undertaking and of great difficulty.

It's worth noting that a feature like this has been discussed as an extension to parameterized extensions (see the Future Directions section) where it would be spelled as:

extension<T: A> T: B {
    // Implementation for `B`
}

Note that parameterized extensions are themselves not yet a part of the language, so even if this direction were pursued it would be a long way off.

1 Like

Hm. I see...

The problem I see with this is (as far as my two cents are worth)

  1. it doesn't work as one would intuitively expect
  2. it makes a rather weak point in favor of protocol-oriented programming (vs using class inheritance), since subclassing would lend itself perfectly to the above example, as demonstrated in the snippet below

Snippet:

class A {
    var name: String {
        "Deafult name"
    }
}
class Foo: A {}
class Bar: A {}

extension A: CustomStringConvertible {
    var description: String {
        name
    }
}

Do I understand it correctly then, that if I were to chose to work with protocols (and structs) instead of classes I am well out of luck, and need to add CustomStringConvertible to each type by hand?

Depends on what you mean by "by hand". You can write the protocol extension with the implementation once, and then write out the conformance for each relevant type, e.g.,

protocol A {
    func foo()
}

protocol B {}

extension B {
    func foo() {
        // some reasonable default implementation
    }
}

extension Int: A, B {}
extension String: A, B {}
// etc.
1 Like
Terms of Service

Privacy Policy

Cookie Policy