Ugh, automatic Equatable conformance and Strideable

I just spent hours looking for a bug caused by an infinite loop when adding Strideable support. I started with:

struct MyType {}
extension Equatable {}
extension Hashable {}

I added tests that call the automatically generated equality and hash members. Then I added AdditiveArithmetic, Numeric, SignedNumeric, and Comparable, with more tests. When I added Strideable support, with the type acting as its own Stride, my distance(to:) method was going into an infinite loop.

I knew that Stridable's methods call each other when a conforming type is its own Stride, and you need to manually define at least one to break the loop. I forgot that this:

extension Equatable {}

doesn't mean activate the automatically-defined version. It means that I'm declaring conformance, and the definition was defined earlier (in either the primary definition or another extension) or will be defined in a later extension, and then use an automatic definition if no block defines one. Since Strideable provides a ==, that cancels the automatic version in favor of its defaulted import and therefore triggers the infinite recursion danger.

In my new-type proposals, I mentioned copying all of the members across that match a protocol with:

newtype MyNewType: MyOldEquatableType {
    publish Equatable
    //...
}

I wonder if it's too late to do a similar syntax with the automatic conformance:

struct MyType: Equatable {
    // Put various Equatable stored properties here.

    publish default Equatable
}

so we can't get ambushed by refined protocol conformances with default implementations stealing our assumed per-member implementations away. And hopefully find a transition plan to remove the current semi-implicit method of automatic definitions.

1 Like

Added a bug report, TF-786: "Automated conformance can be hijacked by extension protocol conformances that import matching members."

Terms of Service

Privacy Policy

Cookie Policy