Pre-release Harn is pre-1.0 — the language, standard library, and CLI may change between releases. See the release notes

Runtime values

TypeSyntaxDescription
string"text"UTF-8 string
bytesbuiltin-producedImmutable byte buffer
int42Platform-width integer
float3.14Double-precision float
decimaldecimal("0.10")Exact base-10 number (96-bit) for money/precise arithmetic. No literal syntax — constructed via the decimal() builtin. Arithmetic promotes int exactly but never mixes with float (a type error); equality/ordering compare only against decimal (scale-insensitive). Excluded from the number alias.
number42 / 3.14Built-in alias for int | float (does not include decimal)
booltrue / falseBoolean
nilnilNull value
list[1, 2, 3]Ordered collection
dict{key: value}String-keyed map
setset(1, 2, 3)Unordered collection of unique values
closure{ x -> x + 1 }First-class function with captured environment
enumColor.RedEnum variant, optionally with associated data
structPoint({x: 3, y: 4})Struct instance with named fields
task_handle(from spawn)Opaque handle to an async task
Generator<T>regular fn containing yieldExisting synchronous generator value
Stream<T>gen fn containing emitLazy, single-pass stream value
Iter<T>x.iter() / iter(x)Lazy, single-pass, fused iterator. See Iterator protocol
Pair<K, V>pair(k, v)Two-element value; access via .first / .second

Truthiness

ValueTruthy?
bool(false)No
nilNo
int(0)No
float(0)No
string("")No
bytes(b"")No
list([])No
dict([:])No
set() (empty)No
Everything elseYes

Equality

Values are equal if they have the same type and same contents, with these exceptions:

  • int and float are compared by converting int to float
  • Two closures are never equal
  • Two task handles are equal if their IDs match

Comparison

int, float, decimal, and string support ordering (<, >, <=, >=). int and float order numerically against each other; decimal orders only against decimal. Two compound values order structurally:

  • Pair compares .first, then .second on a tie.
  • list compares lexicographically, element by element; if one list is a strict prefix of the other, the shorter list orders first. This is what makes multi-key sorts like xs.sorted_by({ x -> [x.a, x.b] }) order by the first key, then the second.

An unordered element (a float NaN, directly or nested inside a pair or list) makes the whole comparison unordered: relational operators return false, while sorting-style total-order reductions (sorted, sorted_by, min, max) treat the operands as equal so a stray NaN cannot destabilize a sort. Comparison between other type combinations returns 0 (equal).