Documentation/Reference

Value equality, ordering, hashing and display

On this page

Canonical operators define a nominal type’s public value behavior. Declare them in the type’s defining module. Ordinary functions with the same names do not register operators. Each operation takes required read-only operands of the exact type; it cannot have generic parameters, defaults or escaping checked failures.

Declaration Result Used by
OPERATOR Equal(a AS T, b AS T) BOOLEAN Equality expressions, searches and key comparison
OPERATOR Compare(a AS T, b AS T) CompareResult Ordering, comparisons and default sorting
OPERATOR Hash(value AS T) INTEGER or UINT64 Hash-based set/dictionary lookup
OPERATOR Display(value AS T) STRING PRINT, interpolation, explicit Display and logging

Chapter 13 contains complete examples. Default copyable-record equality compares fields recursively. Custom Equal disables automatically generated Hash and Compare, so supply coherent versions when the type needs them. Compare without Equal derives equality from CompareResult.Equal, but still needs a compatible Hash for hash-key use. Explicit per-sort comparators are a separate policy.

Equal keys must hash identically. Equality and ordering must obey their normal mathematical laws: symmetry, transitivity and consistency with equality. The compiler checks signatures and allowed effects; it cannot prove arbitrary laws in your code. Incorrect laws can produce wrong collection results or poor performance without bypassing memory safety.

Unordered values and keys

CompareResult has Less, Equal, Greater and Unordered alternatives. A custom Unordered result makes ordered relations false. Default sorting with a custom Compare that reports Unordered raises UnorderedComparisonError and preserves the original input. Default DOUBLE sorting separately uses a NaNs-last policy. Sorting ties do not imply IEEE equality.

NaN is rejected in set members and dictionary keys, including nested fields, independently of a custom operator ignoring that field. Signed zero is one key; infinities are valid. Resource equality, ordering and hashing are rejected. Display alone does not make a resource copyable, comparable or hashable.

Predictable effects

Operator bodies can compute, allocate and change their own locals. They cannot perform I/O, inspect clocks/randomness or mutable native state, modify external storage, start tasks, explicitly suspend, or invoke unsafe/unverified foreign operations. These restrictions also apply to helpers they call. Indirect function calls are conservatively restricted; NOSUSPEND alone does not prove purity. The checks apply even when an operator is unused.

Ordinary task scheduling can still occur at compiler-generated safe points. Equality/hash/comparison operations complete their enclosing collection work before acknowledging cancellation. A long-running custom operator can therefore delay cancellation. Display follows ordinary checked call cleanup and can acknowledge cancellation while rendering. Neither policy establishes termination or a hard response-time guarantee.

Displaying nominal values

Display returns independent text while borrowing its operand, including a resource. No automatic field dump, implicit concatenation or arbitrary STRING conversion is added. Width, alignment, fill and precision apply to the returned text as STRING formats; numeric specifications are rejected. A derived record needs its own Display declaration: ordinary extension does not introduce virtual dispatch.

Direct nominal logging arguments are displayed after severity filtering and once per argument even if a field is repeated. Explicit Display/LogArgument calls are ordinary eager expressions. A deferred zero-argument function runs after filtering and retains its real checked failures. Display does not transfer the operand or extend an escaping resource borrow.

Explicit Display also supports strings, numeric scalars, BOOLEAN and UUID. BOOLEAN conversion uses True/False; existing scalar PRINT spelling is unchanged. Erased root Error does not dynamically discover a descendant’s display hook. Compatible BASIL packages preserve declared capabilities; older tools may require a rebuild or upgrade for newly supported declarations.

From the BASIL documentation. View source ↗

Find your way around BASIL

Type to search the manual.