Eq and Ord Are Traits of the Language, a Bound on Them Gives the Operators, and a Program Writes impl Eq and impl Ord for the Types It DeclaresStatus: Accepted
Date: October 12, 2026 (#592)
Answers: whether a generic function can ask that its type be comparable
([T: Ord]), what the bound gives the body, and who answers it
Related:
ADR-204 (a type compares when its parts do; == on one that does
not is NK1188),
ADR-010 D10 (a map kept in order asks its key for an order),
ADR-295 D7-D8 (a bound is written [T: Trait] and answered from
the ledger),
Part I 4.7
Can a generic function say that its type is comparable, and what does the bound give the body?
fn biggest[T: Ord](a: T, b: T) -> T {
if a > b { return a }
return b
}
Today this is refused with NK1135 (there’s no trait called Ord). Without
the bound, a > b on a T passes the checker and is refused by rustc
(binary operation > cannot be applied to type T), which is Part III C.1:
an error about generated code reaches the user. Libraries that want to accept
“anything sortable” or “any key that can be ordered” have nothing to write.
| Language | Its answer | Source |
|---|---|---|
| Rust | traits Eq, PartialOrd, Ord with cmp -> Ordering; #[derive] or a hand-written impl; a bound gives the operators; the orphan rule limits an impl to a local type or a local trait |
from memory, not checked |
| Swift | protocols Equatable, Comparable; a type conforms by writing == and < |
from memory, not checked |
| Haskell | classes Eq, Ord with an instance per type; compare -> Ordering |
from memory, not checked |
| Go | built-in constraints comparable and cmp.Ordered; no user conformance, a type is in or out by its kind |
from memory, not checked |
| Kotlin, Java | Comparable<T>.compareTo; the operators are the method by convention (Kotlin) or absent (Java) |
from memory, not checked |
| Question | Option | Why it lost / won |
|---|---|---|
| who answers a bound | the language alone, from its own walk (Go) | lost: a program could never say what order its own type has, and a library could not offer one |
the language for its own types, and the program through impl |
won: the owner’s decision; the language’s walk stays the answer where nobody wrote an impl |
|
| what the bound gives | the method only (a.compare(b)) |
lost: the bound exists to make a > b legal in the body |
| the operators | won: the owner’s decision; it is what a reader expects of [T: Ord] |
|
| the order’s method | less(self, other) -> bool |
lost: an ordered map needs a three-way answer, and less asked twice costs two calls per step |
compare(self, other) -> Ordering |
won: one call per step, as every language above that has a three-way answer | |
| an order for a declared type that nobody wrote | field order, derived | lost: it makes the order of the fields a promise nobody asked for (ADR-010 D10) |
none until impl Ord |
won | |
| the set of standard bounds | Eq, Ord, Hash, Copy, Display, Iterator |
lost: the last three carry methods and semantics of their own |
Eq and Ord |
won: the owner’s decision; Hash follows with the hash-map key check (#591) |
Eq and Ord are traits of the language, in scope everywheretrait Eq { fn eq(ref self, other: ref Self) -> bool sync }
trait Ord { fn compare(ref self, other: ref Self) -> Ordering sync }
enum Ordering { Less, Equal, Greater }
They are Rust’s own, not look-alikes. A trait method without sync lowers to
an async fn, which no Rust generic function over T: Ord can call, so both
are sync and lower to the standard library’s: Eq to PartialEq and Eq
(eq), Ord to PartialOrd and Ord (compare is cmp), Ordering to
std::cmp::Ordering. A bound [T: Ord] is Rust’s T: Ord. A Nikaia type with
an impl Ord is therefore an Ord type to Rust code (a BTreeMap key, a
sort), and a Rust type whose ledger says orders = true satisfies the bound.
PartialEq and PartialOrd are not named: a float is compared with == and
< where its type is known, and has neither trait here.
Self is the implementing type. A program that declares a trait or an enum of
one of these names keeps its own, as it does for any word the language uses
(ADR-298). Nothing is imported: they are named the way String is.
[T: Eq] gives == and != on two T. [T: Ord] gives <, <=, > and
>=, the method compare, and also == and !=: an ordered type is an Eq
one, as in Rust. A float is neither (NaN), so a T: Ord is never an f64;
< on a concrete f64 stays what it was.
NK1248a < b on a T with no Ord bound is refused where it is written, naming the
bound that would allow it (< needs T: Ord). It is the same refusal for
== and Eq.
impl, and where there is none by the language, from the type’s partsbool,
char, String and Bytes are Eq and Ord, a float is neither, and a
container (Vec, List, Array, Option, a tuple, BTreeMap, BTreeSet)
answers exactly when what it holds does (Ord lexicographically).Eq by the walk of ADR-204 D1-D2, with no impl
written, and Ord only through an impl Ord. A type that holds one that
is not Eq is not Eq either, and an impl Eq for it is how a program says
that it is.orders = true for Ord
(ADR-010 D10) and equates = true for Eq. Absence is no (ADR-010 D1).
ADR-204 D2 left the second column for the day something needed it; this is
that day.impl Eq and impl Ord are written for a type the program declaresAn impl Eq for P replaces the equality the walk would have derived for P;
an impl Ord for P gives P an order. For a type another package declares the
ledger answers, and an impl of these two traits for it is refused (NK1249,
the orphan rule of the language below). impl Ord for P is refused (NK1249)
where P is not Eq, by the walk or by an impl Eq.
A body that can pause is refused (NK1129): the bridge is not asynchronous.
The laws are the program’s: equality is reflexive, symmetric and transitive; the
order is total and compare answers Equal exactly where eq answers true.
The compiler does not check them. A type that breaks them gives an ordered map
no meaning, and the language says so rather than refusing what it cannot see.
OrdNK1247 (ADR-010 D10) is the question is the key Ord, answered by D4. A
declared type is no longer refused as a key where the program wrote impl Ord
for it.
Comparable), plus
the impls of the two traits from the program’s ledger and the libraries’.impl PartialEq/Eq and impl PartialOrd/Ord for an
impl Eq/impl Ord (partial_cmp is Some(cmp)), and omits the derive an
impl Eq replaces.orders column stays; equates is new, written by nikaia describe
where the crate derives Eq.a < b on an unbounded T stops reaching rustc.Hash as a bound, and the hash-map key check (#591). The key check is
decided by ADR-010 D11 and D12 (a declared type hashes from its
fields, and by its impl Hash where it has an impl Eq); Hash as a bound
stays open.Copy, Display, Iterator as bounds.Ordering (reverse, then), min, max, sort over Ord:
library entries, asked when a program needs them.trait Map[K, V], #593) and supertraits written by a
program: Ord implying Eq is a rule of the language here, not a mechanism.