Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-14665] Synthesised Equatable may be incorrect for manually implemented Comparable #57016

Open
WowbaggersLiquidLunch opened this issue May 26, 2021 · 2 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself derived conformances Feature → protocol → conformances: derived conformances aka synthesized conformances

Comments

@WowbaggersLiquidLunch
Copy link
Collaborator

Previous ID SR-14665
Radar None
Original Reporter @WowbaggersLiquidLunch
Type Bug
Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, DerivedConformance
Assignee None
Priority Medium

md5: 7c4663ac0f4ead1b689e43c0ea8393a3

relates to:

  • SR-11588 Warn about derived Hashable implementation if there's a custom Equatable

Issue Description:

Currently Comparable inherits from Equatable, but does not provide a default implementation for ==, so the compiler synthesizes one composed of member-wise ==s. This leads to a problem where if a type's < is not composed of member-wise inequalities, then <, >, and == can all evaluate to false for some pairs of values, contradicting Comparable's documentation:

Types with Comparable conformance implement the less-than operator (<) and the equal-to operator (==). These two operations impose a strict total order on the values of a type, in which exactly one of the following must be true for any two values a and b:

  • a == b

  • a < b

  • b < a

For example:

struct Length: Comparable {
    enum Unit: Double, Comparable {
        case mm = 0.001
        case m = 1
        case banana = 0.178
    }
    
    let magnitude: Double
    let unit: Unit
    
    static func < (lhs: Self, rhs: Self) -> Bool {
        lhs.magnitude * lhs.unit.rawValue < rhs.magnitude * rhs.unit.rawValue
    }
}

let aBanana = Length(magnitude: 1, unit: .banana)
let oneBanana = Length(magnitude: 0.178, unit: .m)

print(aBanana < oneBanana)  // prints "false", because Length's < says so.
print(aBanana > oneBanana)  // prints "false", because Comparable's default implementation of >(a,b) is <(b,a).
print(aBanana == oneBanana) // prints "false", because the 2 Length instances are not member-wise equal.

Forums discussion: https://forums.swift.org/t/add-default-implementation-of-to-comparable/48832

@WowbaggersLiquidLunch
Copy link
Collaborator Author

submitted a draft PR #39047 #39047

@WowbaggersLiquidLunch
Copy link
Collaborator Author

I haven't had time in the past few months to continue working on this, and don't think I will be anytime soon, so I unassigned myself. If anyone wants to take over, please feel free to do so.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
WowbaggersLiquidLunch added a commit to WowbaggersLiquidLunch/swift-docc-symbolkit that referenced this issue Jun 4, 2022
Reference to [SR-14665](apple/swift#57016) links to more explanation on why the manual `==` implemenatation is necessary.
WowbaggersLiquidLunch added a commit to WowbaggersLiquidLunch/semantic-version that referenced this issue Jun 4, 2022
[SR-14665](apple/swift#57016) links to more detailed explanation on why manual `==` implementation is necessary.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself derived conformances Feature → protocol → conformances: derived conformances aka synthesized conformances
Projects
None yet
Development

No branches or pull requests

1 participant