Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Traits

A trait names a contract a type can implement, in the style of Rust traits — but its implementations are rules, not methods. The fourth atom is a rule-plane construct: a trait declares one or more rule heads, and each impl … for T supplies a clause for a specific type. The clauses for a given head union exactly as same-head derive clauses do, so the implementations behave as one rule with per-type behavior:

pub trait Inspectable {
    derive Due(Self);
}

impl Inspectable for Truck { derive Due(t: Self) :- t.hours >= 100; }
impl Inspectable for Crane { derive Due(c: Self) :- c.hours >= 50;  }
impl Inspectable for Drone { derive Due(d: Self) :- d.hours >= 10;  }

Dispatch is not a vtable lookup; it is derivation. The reasoner fires whichever per-type clauses match, so a query over Due returns every asset past its own kind’s threshold — three clauses, one head, per-kind thresholds. A trait may require another, Rust’s supertrait bound: trait Serviceable: Inspectable makes implements(t, Serviceable) entail implements(t, Inspectable), and the reflective surface — implements(t, Trait) as a body atom — ranges over the catalog like any other relation.

Conformance is checked at the catalog layer. A #[static] check whose variables are all reflective-sorted — a TypeRef ranging over the type catalog, reading specializes and implements — discharges totally at ox check and ox build, with no instances. So a package can demand that every kind under a category implement a contract and have the demand settled at build:

#[static]
pub check EveryAssetKindIsInspectable(t: TypeRef) :-
    specializes(t, Asset), t != Asset,
    not implements(t, Inspectable)
    => Diagnostic { severity: Severity::Error, code: "Fleet::E010",
                    message: format!("{} must implement Inspectable", t) };

The check fires on any asset kind left uncovered and refuses the build before an artifact is written; #[static] makes instance-vocabulary drift a hard error rather than a silent reclassification. A trait is not a concept — it carries no extent and classifies no individual — so a bare trait-head atom over a type only partially covered is itself a build error unless the author writes the coverage-can-fail branch explicitly, never by silence. Argon by Example works a fleet under trait contracts in trait_contracts. The reference fixes the trait surface and its conformance discipline under the trait atom.