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.