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

First-class relations

Area: Relations Teaches: relations are first-class constructs — n-ary, with their own properties, cardinality, specialization, and rule participation. Prerequisites: concepts and <: (see concepts and hierarchies). Run: ox build examples/first_class_relations && ox query examples/first_class_relations

In most data languages a relationship is a second-class thing: a foreign key with no identity and no data of its own, or something you reify by hand into a stand-in node. Argon makes a relation a construct, declared with a rel keyword exactly as a concept is declared with a type keyword. An edge has the same standing as a node.

What to read in root.ar

A relation carries its own data. An employment has a salary — the salary belongs to the relationship, not to the person or the org:

pub rel Employment(employee: Person, employer: Org) { mut salary: Int };

Cardinality is per endpoint (UML association-end multiplicity — the i-th bracket bounds the distinct position-i values for a fixed combination of the other endpoints): [0..1] on the owner slot means an asset has at most one owner, and [0..*] on the asset slot means a person may own any number.

pub rel Owns(owner: Person, asset: Asset) [0..1] [0..*];

Relations are n-ary, not just binary — a sale relates three participants without an intermediate node:

pub rel Sale(seller: Person, buyer: Person, item: Asset);

Relations specialize, like concepts — every internship is an employment:

pub rel Internship(employee: Person, employer: Org) <: Employment;

Relations participate in rules, read in a rule body exactly as a concept’s extent is:

pub derive colleagues(a: Person, b: Person) :- Employment(a, o), Employment(b, o);

Running it

With Alice and Bob both employed by Acme, colleague_pairs returns the four pairings the rule derives — including each person with themselves, since the rule as written does not exclude a = b (adding an inequality guard is a natural exercise).

Honest caveats (what runs today)

  • Maximum cardinality is enforced at the write path; a minimum above zero (e.g. [1..1]) is recorded on the wire but not yet enforced in v0 — ox check emits OW1342 naming the relation and position. This example uses [0..1] / [0..*], so it has no unenforced minimum.

This example is compiled and run in CI — the corpus auto-discovery parses and resolves it, and a corpus test (oxc-runtime/tests/examples_corpus.rs) pins the colleague_pairs behaviour to exactly the four pairings the rule derives. If the language changes underneath it, the build breaks rather than the docs going stale.