Skip to content

Traits

Contracts used by operators, collections, iteration, conversion, cleanup, and selection.

Updated View as Markdown

The prelude’s traits connect generic algorithms and language syntax. Dispatch is static: generic uses are monomorphized for concrete types, and there is no current dyn Trait or vtable surface.

Trait Contract
Equatable Equality through equals
Hashable Hash consistent with equality
Comparable[T] Total ordering through compare_to
Display, Debug Human and developer text
Numeric Arithmetic and numeric conversion
Neg, Not, BitNot Unary operators
BitAnd, BitOr, BitXor, Shl, Shr Bitwise operators
Index[K, V], IndexMut[K, V] Indexed read and write
Default, Clone Construction and copying
From[T], Into[T] Conversion
Iterator[T], Iterable[T] One-shot and repeatable iteration
Bytes, Buffer Byte views and builders
Drop User cleanup before storage release
Selectable[T] Value that can participate in select

Operator resolution uses direct primitive operations first and trait dispatch for user-defined operands.

struct Money { cents: int }

impl Equatable for Money {
    fn equals(self, other: Money): bool {
        return self.cents == other.cents
    }
}

impl Display for Money {
    fn to_string(self): string {
        return "${self.cents} cents"
    }
}

Collection bounds are meaningful: map keys and set members require Hashable; sorting requires Comparable; numeric aggregation requires Numeric. Implement the narrowest contracts a type actually satisfies.

Drop.drop runs as part of compiler-managed cleanup, including cancellation paths. It is for releasing external resources, not for manually balancing the compiler’s reference counts.

Contract laws

The type checker verifies signatures, not semantic laws. Implementations must preserve the laws expected by algorithms:

  • Equatable should be reflexive, symmetric, and transitive;
  • equal Hashable values must return the same hash code;
  • Comparable should agree with equality when compare_to returns zero;
  • Clone should produce an independently usable value;
  • Display should remain suitable for users, while Debug can expose structure.

Violating equality and hashing laws can make map entries and set members unreachable even though the program still type-checks.

Operators

For non-primitive operands, syntax routes through trait methods:

Syntax Trait method
left == right Equatable.equals
left < right Comparable.compare_to
-value Neg.neg
!value Not.not
left & right BitAnd.bit_and
left << amount Shl.shl
value[key] Index.get
value[key] = item IndexMut.set

Primitive numeric operations continue through direct compiler lowering. Implementing a trait does not replace those primitive paths.

Conversion

From[T] constructs the implementing type from T; Into[T] converts a receiver to T. Atoll does not apply arbitrary user conversions silently. Call conversion methods explicitly at API boundaries so allocation, failure, and precision changes remain visible.

Default.default() supplies a canonical zero or empty value. It does not imply that every instance can be reset safely by overwriting it with a default.

Iteration

Iterator[T] defines mutable next(): Option[T]; Iterable[T] creates an associated iterator. Default iterator methods implement traversal and lazy map/filter/take/skip adapters.

Byte protocols

Bytes exposes a pointer and length for read-only binary values. Buffer adds mutation and formatted appends. These traits let strings, lists, slices, and host APIs share binary operations without a separate nominal byte-buffer class.

Bytes is implemented by owned and borrowed byte sequences. Buffer is the growable super-surface implemented only by owned []byte.

Selection

Selectable[T] is structural:

trait Selectable[T] {
    fn raw_handle(self): usize
    fn await(self): T
}

Task[T] and Stream[T] satisfy it. Application implementations must also honor scheduler handle, readiness, and consumption invariants, so this is primarily a runtime extension point.

await() on a stream consumes its next item according to stream readiness; await() on a task waits for completion. select uses raw_handle() to register readiness with the scheduler before evaluating the winning arm.

Cleanup

Drop.drop cannot suspend. Standard resource wrappers therefore make close synchronous even when their ordinary I/O methods can suspend. A custom Drop implementation must be safe to run during early return and error propagation.

See Traits for declarations, bounds, and associated types, and Implementations for coherence and method resolution.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close