swift-primitives/swift-comparison-primitives
Comparison — a three-way comparison value type with .less / .equal / .greater cases — and Comparison.Protocol, an ordering protocol that admits ~Copyable types via borrowing parameters. Mirrors Swift.Comparable and, on Swift 6.4 and later, is Swift.Comparable
Key Features
- Three-way comparison value type — A dedicated
Comparisonenum beats the C-stylenegative / zero / positiveIntconvention: the type system enforces the domain, the cases carry semantic meaning, and the operations (reversal, monoidalthen, query properties) have algebraic structure that integers don't. - Move-only ordering —
Comparison.Protocollets~Copyabletypes implement<and==withborrowingparameters. Default<=,>,>=come from the protocol's extension. - Fluent
.compareand.clampaccessors —value.compare.to(other),value.compare.isLess(than: other),value.clamp.between(low, and: high)work on both stdlibComparabletypes and on customComparison.Protocolconformers. - Lexicographic composition —
.then(_:)and.then(with:)build sort comparators across multiple fields in a single expression. - SE-0499 dual-mode — Under Swift <6.4, the package ships its own protocol fork. Under Swift 6.4+,
Comparison.Protocolis a typealias toSwift.Comparable. Conformances written today work on both compiler families.
Quick Start
Compare two values via the three-way result type:
import Comparison_Primitives
let result = Comparison(comparing: 5, to: 10) // .less
result.reversed // .greater
!result // .greater (prefix !)Compose comparisons lexicographically across multiple fields. then is the monoid operation under .equal as identity:
struct Person { let name: String; let age: Int; let id: Int }
func compare(_ lhs: Person, _ rhs: Person) -> Comparison {
Comparison(comparing: lhs.name, to: rhs.name)
.then(Comparison(comparing: lhs.age, to: rhs.age))
.then(Comparison(comparing: lhs.id, to: rhs.id))
}A move-only token type conforms to the ordering protocol with borrowing parameters:
struct Token: ~Copyable, Comparison.`Protocol` {
let priority: Int
static func < (lhs: borrowing Token, rhs: borrowing Token) -> Bool {
lhs.priority < rhs.priority
}
static func == (lhs: borrowing Token, rhs: borrowing Token) -> Bool {
lhs.priority == rhs.priority
}
}
var a = Token(priority: 5)
let b = Token(priority: 10)
let isLess: Bool = a < b // true
let result2 = a.compare.to(b) // .lessThe fluent .compare accessor works on stdlib Comparable types too:
var apple = "apple"
let banana = "banana"
apple.compare.to(banana) // .less
apple.compare.isLess(than: banana) // true.clamp mirrors the shape for bound-restriction:
var temperature = 105.0
temperature.clamp.between(0.0, and: 100.0) // 100.0
temperature.clamp.above(110.0) // 110.0Installation
Add the dependency to your Package.swift:
dependencies: [
.package(url: "https://github.com/swift-primitives/swift-comparison-primitives.git", branch: "main")
]Add the umbrella product to your target:
.target(
name: "App",
dependencies: [
.product(name: "Comparison Primitives", package: "swift-comparison-primitives")
]
)For narrower surface, depend on Comparison Primitives Core alone (value type + protocol, no stdlib bridge for fluent accessors).
Requires Swift 6.3.1 and macOS 26 / iOS 26 / tvOS 26 / watchOS 26 / visionOS 26 (or the corresponding Linux / Windows toolchain).
Architecture
Four library products plus a Test Support target:
| Product | Contents | When to import | |---------|----------|----------------| | Comparison Primitives | Umbrella — re-exports Core + Standard Library Integration | Most consumers | | Comparison Primitives Core | Comparison value type, Comparison.Protocol, Comparison.Compare, Comparison.Clamp (without stdlib Comparable bridge) | When stdlib .compare / .clamp are unwanted | | Comparison Primitives Standard Library Integration | Re-conformance of stdlib types under Swift <6.4; the Swift.Comparable bridge that powers .compare / .clamp on stdlib types | Pulled in transitively by the umbrella | | Comparison Primitives Test Support | Re-export of upstream Test Support modules | Test target only |
The fluent .compare and .clamp accessors are backed by the Property.Inout pattern — fluent namespaces without per-type proxy structs, extensible from downstream code.
Stability
Pre-1.0. The 0.1.0 surface — Comparison enum, Comparison.Protocol, Comparison.Compare, Comparison.Clamp, the protocol's reversal/chaining/boolean operations — is committed to source-compatibility through the dual-mode bridge. The Comparison enum and its operations are independent of the SE-0499-driven protocol question; they remain regardless of which compiler your consumer ships against. The eventual long-term shape, post-Swift-6.4-ecosystem-floor, is the protocol's typealias-to-stdlib reduction; the value type stays.
Platform Support
| Platform | CI | Status | |------------------|-----|--------------| | macOS 26 | Yes | Full support | | Linux | Yes | Full support | | Windows | Yes | Full support | | iOS/tvOS/watchOS | — | Supported | | Swift Embedded | — | Supported |
License
Apache 2.0. See LICENSE.md.
Package Metadata
Repository: swift-primitives/swift-comparison-primitives
Default branch: main
README: README.md