Discussion about Infix Operators and Symmetry
Just an observation here specifically WRT the discussion about enforcing semantics across all concrete types:
So the "unstated implication" here is that if we defined this operation through === we are limiting the flexibility that library maintainers might need.
Suppose for example a library maintainer had some code path where they needed to forward === through to Span.isIdentical:
struct S {
static func ===(_ lhs: Self, _ rhs: Self) -> Bool {
guard
lhs.hasStorage,
rhs.hasStorage
else {
return lhs.span.isIdentical(to: rhs.span)
}
return lhs.storage === rhs.storage
}
}
So it's not completely idiomatic here for S to "promote" lhs to be the receiver of the isIdentical operation on span. Unless maybe if Span.isIdentical gave us the formal guarantee of symmetry… which I do not currently see guaranteed in the documentation.
The option then might be to enforce that === must also be an symmetrical operation such that a === b is the same as b === a. But I'm not yet persuaded that symmetry must be enforced at an abstract level across all these operations. I have no problem with library maintainers of a concrete type making that decision for themselves when appropriate to do so. I'm just not convinced we need to always enforce that everywhere.
…
But now that I go back and think through again… there must be some kind of convention here that infix operators do not take labels and still distinguish between arguments. How else could a < implementation not just flip the arguments and return the wrong answer?
It looks like the declaration of === does not formally confirm Reflexivity, Symmetry, or Transitivity:
stdlib/public/core/Equatable.swift
- /// Returns a Boolean value indicating whether two references point to the same
- /// object instance.
- ///
- /// This operator tests whether two instances have the same identity, not the
- /// same value. For value equality, see the equal-to operator (`==`) and the
- /// `Equatable` protocol.
- ///
- /// The following example defines an `IntegerRef` type, an integer type with
- /// reference semantics.
- ///
- /// class IntegerRef: Equatable {
- /// let value: Int
- /// init(_ value: Int) {
- /// self.value = value
- /// }
- /// }
- ///
- /// func == (lhs: IntegerRef, rhs: IntegerRef) -> Bool {
- /// return lhs.value == rhs.value
- /// }
This file has been truncated. show original
So unless maybe that is hiding out somewhere else… we do not explicitly guarantee that x === y must imply y === x. Which is surprising…
I do think that even without this explicit semantic guarantee any product engineer that looks at === probably expects it to respect Symmetry. And if we defined a new set of === operators on these types I think it would be fair to assume those project engineers also expect Symmetry there.