Overriding default protocol implementations

I was recently trying to set up a default implementation for a protocol Foo that could return different values for it's property baz based on if the object also conforms to another protocol Bar. When implementing this below the result is a runtime crash EXC_BAD_ACCESS.

protocol Foo {}

protocol Bar {
    var baz: Bool { get }
}

class FooBar: Foo, Bar {}

class FooBaz: Foo, Codable {}

extension Foo {
    var baz: Bool {
        return (self as? Bar)?.baz ?? false
    }
}

let fooBar = FooBar()
let fooBaz = FooBaz()

func doSomething(with foo: Foo) {
    print(foo.baz)
}

doSomething(with: fooBar)
doSomething(with: fooBaz)

Your definition of baz in the extension calls baz, so itself as there's no other definition, to get its result. So to succeed it needs to recur infinitely.

2 Likes

Here's what's happening:

FooBar conforms to Foo. Foo has an extension with a property baz. Therefore, FooBar contains a member property called baz.

FooBar conforms to Bar. Bar requires an implementation for a property named baz. Since FooBar contains a member property called baz with the same signature as Bar's requirement (the property it got from Foo), the compiler chooses it to fulfill the requirement.

When you get the property baz on an instance of FooBar, it casts self to Bar and then gets its baz property. However, because that Bar's baz property requirement is fulfilled by Foo's baz property, the property ends up calling its getter recursively until the stack overflows.


What do you expect/want the compiler to do here?

4 Likes

AH! Thank you! When I define baz on FooBar the issue in this example stops recursively calling itself. In the situation I was trying to reproduce, I was defining baz as an optional on FooBar resulting in the same issue as above. I just needed someone to point out the obvious :smile:

1 Like