Skip to content

Derive

The derive clause instructs the compiler to generate correct-by-construction implementations of common interfaces. Every hand-written eq or clone method is a chance for error. The compiler never misses.

Supported Derivations

Derive Generated Behavior
Eq Structural equality -- every field compared. Two values are equal if all fields are equal.
Clone Deep copy -- every field cloned recursively.
Display Canonical string representation. Structs format as TypeName{ field: value, ... }.
Hash Structural hash -- every field hashed and combined. Compatible with Eq.
Ord Lexicographic ordering -- fields compared in declaration order.
Debug Debug representation via .fmt(). Defaults to Display output unless overridden.

Usage

type Point = {
  x: Float64;
  y: Float64;
} derive[Eq, Clone, Display]

// Compiler generates:
//   fn Point.eq(other: &Point) -> Bool     -- x == x && y == y
//   fn Point.clone() -> Point              -- deep copy of both fields
//   fn Point.to_str() -> Str               -- "Point{ x: 1.0, y: 2.0 }"

Invariant Restriction

Types with invariant clauses cannot derive Eq, Hash, or Ord. Invariants make structural equality semantically ambiguous -- two values with different internal state may both satisfy the same invariant. Clone and Display remain available.

type Health = {
  current: Int;
  maximum: Int;
  invariant: current >= 0;
  invariant: current <= maximum;
} derive[Clone, Display]
// Eq, Hash, Ord are rejected -- invariants make equality/hashing ambiguous

Enums

Enums support derive too:

enum Option[T] {
  Some(value: T),
  None,
} derive[Eq, Clone]

// Enums with variant data can derive Clone, Display, Debug
// Enums with only unit variants can also derive Eq, Hash, Ord

Codegen Details

Eq

; Structural comparison over all fields
%eq_x = fcmp oeq double %self.x, %other.x
%eq_y = fcmp oeq double %self.y, %other.y
%result = and i1 %eq_x, %eq_y

Clone

; Deep copy via alloca + GEP per field
%clone = alloca %struct.Point
%x_ptr = getelementptr %struct.Point, %struct.Point* %clone, i32 0, i32 0
store double %self.x, double* %x_ptr
; ... repeat for each field

Display

; Canonical string via printf format concatenation
; "Point{ x: 1.0, y: 2.0 }"

Hash

; Multiplicative hash (DJB2 variant) combining all fields
%hash = mul i64 %hash, 33
%hash = add i64 %hash, %field_hash

Ord

; Lexicographic field-by-field comparison with branch dispatch
; Compare field 0 -> if not equal, return; else compare field 1...

Custom Implementations

You can always write a manual implementation instead of using derive:

type Point = { x: Float64; y: Float64 }

fn Point.eq(other: &Point) -> Bool {
  return x == other.x && y == other.y;
}

Manual implementations take precedence over derived ones. This is useful when the structural definition doesn't match the semantic definition (e.g., a type that should compare only a subset of fields).