I wanted my protocol to support ~Copyable implementations, but because it implies Equatable I am unable to. Why is this the case?
Because most protocols in the standard library which were already existed when Copyable
was introduced implicitly refine Copyable
.
Just think about it, the method required by Equatable
is static func == (lhs: Self, rhs: Self)
. To make this method work, the arguments must be copied into the the implementation, this fact immediately conflict with concept of ~Copyable
.
At the moment of this reply, we must define our own protocol to model a non-copyable equitability:
protocol NonCopyableEquatable: ~Copyable {
borrowing func isEqual(to another: borrowing Self) -> Bool
}
struct NonCopyable: ~Copyable {
let value: Int
}
extension NonCopyable: NonCopyableEquatable {
borrowing func isEqual(to another: borrowing Self) -> Bool {
value == another.value
}
}
Of course, one must decide how to specify the semantics for the parameters. Here I think borrowing
should be fine.
@Karoy_Lorentey looked at this fairly recently; there's a couple small details to iron out that prevent simply dropping the requirement. IIRC, other than the question @CrystDragon references, there's also a language limitation where we cannot yet express the necessary availability information on the conformance to say "this refines Copyable when targeting OS releases prior to xxx, but does not require that conforming types be Copyable when building for that release or later."
The default convention for a parameter of Copyable type is not quite the same as borrowing
but it’s similar enough in that there is no ownership transfer. (Except for initializers and setters, whose parameters default to something like consuming
). So it’s possible to generalize Equatable to non-Copyable values without breaking existing binaries that depend on the ABI of the == entry point.