Reference
Syntax
The whole language on one page. Every form below is checked by
a conformance program in spec/conformance, so an example that
stopped compiling would fail the build rather than sit here misleading
somebody.
Declarations
fnA function. The row after
/ is inferred and checked.fn add(a: i64, b: i64) -> i64 {
a + b
}
fn greet(name: str) / {io} {
print("hello, {name}")
}pubVisible outside the module. Types are always visible.
pub fn parse(text: str) -> i64 {
text.parse_int() ?? 0
}let / varA binding.
let cannot be reassigned.let limit = 10
var seen = 0
seen = seen + 1type — structNamed fields. At least one.
type Point = {
x: f64,
y: f64,
}type — sumAlternatives, each with named payload fields.
type Shape =
| Circle(r: f64)
| Rect(w: f64, h: f64)
| Emptytype — aliasAnother name for a type.
type Meters = f64effectAn interface a handler supplies at the call site.
effect Clock {
fn now() -> i64
}interface / implA contract and its implementation.
interface Show {
fn show(self) -> str
}importA module or package. Named by its last path segment.
import json
import crypto_hashconstA module-level value, one for the whole program.
pub let MAX_RETRIES = 5testA unit test, or a property test when it takes parameters.
test "reversing twice is the identity" (xs: [i64]) {
assert(xs.rev().rev() == xs)
}extern fnA C symbol. Tier 3 — every call sits in
unsafe.extern fn getpid() -> i64
extern fn strlen(s: str) -> i64Types
PrimitivesOne integer type, one float, and text is UTF-8.
let a: i64 = 42
let b: f64 = 1.5
let c: bool = true
let d: str = "text"bytesA sequence of 0..255. Distinct from
[i64] on purpose, and writable in place at one byte each rather than eight.let raw: bytes = bytes_of([72, 105])
let from_text = "hi".to_bytes()
var buf = bytes_filled(4, 0)
buf.set(0, 255)
buf.fill(7)
buf.copy_from(2, raw)ListsHomogeneous and growable.
let xs: [i64] = [1, 2, 3]
let empty: [str] = []MapsKeyed, with
get returning an Option.var m: Map[str, i64] = map()
m.set("k", 1)
let v = m.get("k") ?? 0TuplesPositional, reached with
.0.let pair = (1, "one")
let first = pair.0Option
Some or None.let found: Option[i64] = Some(3)
let n = found ?? 0Error unions
T ! E — a value or a failure.fn half(n: i64) -> i64 ! MathError {
if n % 2 != 0 {
fail(NotEven(n))
}
n / 2
}Function types
fn(...) closes up; it is a type, not a call.fn apply(f: fn(i64) -> i64, v: i64) -> i64 {
f(v)
}GenericsSquare brackets, on the declaration.
fn first_of[T](xs: [T]) -> Option[T] {
if xs.len() == 0 {
return None
}
Some(xs[0])
}ref TTier 2 — a generational reference, storable in a struct.
let r = ref(Point{ x: 1.0, y: 2.0 })
let alive_now = alive(r)
release(r)Expressions
Operators
and, or, not are words. ^ is power.let a = 1 + 2 * 3 - 4 / 2 % 3
let b = 2 ^ 8
let c = a > 0 and not (b < 0)ComparisonStructural, on everything comparable.
let same = [1, 2] == [1, 2]ifAn expression: it yields a value.
let label = if n > 0 {
"positive"
} else {
"not"
}matchExhaustive. Arms are newline-separated.
match shape {
Circle(r) -> 3.14159 * r ^ 2
Rect(w, h) -> w * h
Empty -> 0.0
}PatternsLiterals, wildcards, alternatives, and tuples.
match n {
0 -> "zero"
1 | 2 | 3 -> "small"
_ -> "large"
}Closures
|params| body. The body may be a block.let double = |n| n * 2
let total = xs.fold(0, |acc, v| acc + v)Interpolation
{} inside a string. A literal brace is \{}.print("{name} has {xs.len()} item(s)")tryA prefix. Propagates the error branch.
fn load(path: str) -> str ! IoError / {io} {
try read_file(path)
}??The else of an Option or a fallible call. Lazy.
let port = env("PORT") ?? "8080"Pipeline
|> feeds the left into the right.let n = xs |> lenRanges
.. excludes the end, ..= includes it.for i in 0..10 {
print("{i}")
}BlocksA block is an expression; its last line is its value.
let v = {
let a = 2
a * a
}Statements and control
forOver a list, a map or a range.
for x in xs {
print("{x}")
}whileWhile the condition holds.
while queue.len() > 0 {
let _v = queue.pop()
}break / continueLeave or skip an iteration.
for x in xs {
if x < 0 {
continue
}
if x > 99 {
break
}
}returnLeaves the function early.
fn find(xs: [i64], want: i64) -> bool {
for x in xs {
if x == want {
return true
}
}
false
}failTakes the error branch of a
T ! E.fail(NotEven(n))Assignment
=, and the compound forms.var n = 0
n = 5
n += 1
n -= 1
n *= 2
n /= 2Ownership and effects
Parameter modesDefault reads;
inout mutates; own takes.fn read(xs: [i64]) -> i64 { xs.len() }
fn grow(inout xs: [i64]) { xs.push(1) }
fn consume(own xs: [i64]) -> i64 { xs.len() }Effect rowsWritten after
/. Inferred, then checked.fn fetch(url: str) -> str ! IoError / {io, net} {
try http_get(url)
}with / handled_bySupplies a handler for an effect, for one scope.
with Clock handled_by ClockHandler{ now: || 1000 } {
print("{Clock.now()}")
}regionTier 1 — nothing allocated inside may outlive it.
region {
var scratch: [i64] = []
scratch.push(1)
}unsafeTier 3 — where the guarantees stop, named in the source.
unsafe {
let pid = getpid()
}parallel / spawnStructured concurrency: the block waits for its tasks.
parallel {
spawn {
print("one")
}
spawn {
print("two")
}
}Lexical
Comments
// to end of line; /* */ nests; /// documents.// a line
/* a block /* that nests */ */
/// documentation for what follows
fn documented() -> i64 { 1 }NumbersDecimal, hex, underscores, floats and exponents.
let a = 1_000_000
let b = 0xFF
let c = 1.5
let d = 1e-9StringsDouble-quoted, with escapes;
""" for raw.let s = "a\tb\n"
let raw = """no escapes here"""Statement endsA newline ends a statement. A line may continue if it ends with an operator.
let total = 1 +
2 +
3IdentifiersLetters, digits and
_; not starting with a digit.let snake_case = 1
let _ignored = 2One namespace for types. Every type is
reachable from every module, which is why pub means nothing on
one — and why two packages cannot both declare a Node. A generator
checks the whole package set for that collision on every build.
The language reference gives the rules behind these forms; the specification gives the clause and the conformance program for each.