Can a subclass implement its own requirement of a protocol adopted by superclass?

This is related to the new Swift 5.2 feature:

A method override can no longer have a generic signature with requirements not imposed by the base method. For example, the below code produces an error. (23626260) (FB5382462)

Unfortunately I inherited a project that is greatly impacted by this change. I'm aware of the bad code for a longer time but the refactor is scheduled to be addressed no sooner than in Q3/20. I'm now looking for some workaround that would allow me to move to Swift 5.2 before the great refactor. And I hit something that I'm now not sure if I'm thinking wrong or violating some principle or it is just not implemented yet this way.

What I'm expecting is ability to implement a protocol requirement adopted by superclass.

protocol Fooable {
    associatedtype BarType
    func foo(_ value: BarType)
}

class Bar {}
class SubBar: Bar {}

class Base: Fooable {
    func foo(_ value: Bar) {
        print("I'm Base accepting Bar but actually I'm \(type(of: self)) and received     \(type(of: value))")
    }
}

class SubBase: Base {
    func foo(_ value: SubBar) {
        print("hmm...")
        super.foo(value)
    }
}

func baz<T>(_ value: T, argument: T.BarType) where T: Fooable {
    value.foo(argument)
}

When I call baz(SubBase(), argument: SubBar()) there is no "hmm..." in the console but only "I'm Base accepting Bar but actually I'm SubBase and received SubBar".

  • So protocol conformance isn't actually inherited but forbidden? Is this why initializer requirement in protocol imposes required initializer for classes?

SubBase.foo & Base.foo are unrelated functions here - I presume you wanted SubBase.foo to implement the foo protocol requirement, but that isn't possible as subclasses do not get witness tables. So, what you need to do is to override Base.foo here. However, when overriding, the function arguments are supposed to be contravariant (so you cannot have subtypes). So, what you need to do is to add the override keyword to SubBase.foo and fix the argument types, in order for it to override Base.foo and then the correct messages will be printed as per your expectation.

Thanks I guess this answers it.

I'm trying to avoid overriding and looking for a kind of parameter covariance but driven by protocol so it doesn't violate the Liskov principle. But I think this is a dead end.

The only solution is to conform the associated type to the base type.

Terms of Service

Privacy Policy

Cookie Policy