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

Language Tour

A tour of the surface syntax. Every example below is real syntax the project documents; none is invented for this page.

Tier annotations

// Default: HIGH, no annotation needed for most code
fn handle_request(req: Request) Response {
    let user = fetch_user(req.user_id)
    return Response.ok(user.to_json())
}

// Opt into MID for a hot path
@tier(mid)
fn parse_payload(body: string) ParsedData {
    with arena(1MB) { }
}

// Opt into LOW for systems code
@tier(low)
fn write_packet(buf: &mut [u8]) usize {
    // raw ownership; borrow checker enforcement is still in progress
}

Collections

Collection names follow C# convention rather than Rust’s.

let mut numbers = List.new()
numbers.push(1)
numbers.push(2)

let mut scores = Dictionary<string, int>.new()
scores.set("Alice", 100)   // set/get, not insert, for symmetry

let items = [1, 2, 3, 4, 5]
let names = ["Alice", "Bob"]   // inferred as List<string>

Unified member access

There is no ::. Type-level calls and instance calls both use ..

summon std.collections.List
let list = List.new()   // type-level call
list.push(42)            // instance call

Error handling

A trailing ! on a return type means the function may fail; ? propagates a failure out of the current function.

fn parse_int(s: string) int! {
    // returns a Result-like value
}

fn process(s: string) int! {
    let n = parse_int(s)?
    return n * 2
}

Async

Async is HIGH tier only. MID and LOW are synchronous by design: arenas have lexical lifetimes, which do not compose with the way an async function suspends and resumes across await points.

@tier(high)
async fn fetch_user(id: int) Task<User>! {
    let resp = await http_get($"/users/{id}")?
    return await parse_user(resp.body)?
}

Structs and methods

struct Rectangle {
    width: int,
    height: int

    pub fn new(w: int, h: int) Rectangle {
        return Rectangle { width = w, height = h }
    }

    pub fn area(self) int {
        return self.width * self.height
    }
}

Pattern matching

match response {
    Ok(data) where data.status == 200 => process_success(data),
    Ok(data) => log_warning($"Status: {data.status}"),
    Err(NetworkError(extract { code, message })) => {
        log_error($"Network error {code}: {message}")
    }
    Err(e) => log_error($"Unknown: {e}"),
}

Pipe operator

let result = data
    |> parse?
    |> validate?
    |> transform
    |> save

Extension functions

extend int {
    fn is_even(self) bool { return self % 2 == 0 }
}

if 42.is_even() { println("Even!") }

References and lifetimes (LOW tier)

&/ref and &mut/ref mut are dual spellings of the same borrow operator, */deref likewise for dereference, the same relationship and/&& and or/|| already have. Either spelling compiles to the identical AST node; named lifetimes are only needed for cross-function borrows complex enough that inference cannot resolve them alone.

// inferred, no annotation needed
fn first(list: &List<int>) &int {
    return &list[0]
}

// same thing, keyword spelling
fn first(list: ref List<int>) ref int {
    return ref list[0]
}

// explicit lifetime for a genuinely ambiguous case
fn longest[lifetime L](x: &L str, y: &L str) &L str {
    if x.len() > y.len() { return x } else { return y }
}

The syntax and structural typing for references are complete. The borrow checker that actually verifies a program’s borrows are sound (loan tracking, liveness, move checking) is still in progress; see The Tier Model for exactly where that line sits today.

RAII with using

using let file = File.open("data.txt") {
    let content = file.read()
    process(content)
}   // file.close() runs automatically

Query pipelines

Linqerizer<T> is a lazy, chainable query pipeline over any collection, HIGH tier only. .query() snapshots the source once; nothing runs until a terminal call (.to_list(), .first(), .count()) walks the pipeline, and each chained call returns a new pipeline rather than mutating in place.

@tier(high)
fn active_adult_names(users: List<User>) List<string> {
    return users.query()
        .where(fn(u) u.age >= 18 and u.status == "active")
        .order_by(fn(u) u.name)
        .select(fn(u) u.name)
        .to_list()
}

.group_by(...) produces a real Dictionary<Key, List<Value>>. An earlier query-comprehension grammar (from x in ... where ... select, closer to C#’s LINQ syntax) was removed outright rather than kept alongside this: it was eager, List-only, group_by was a stub, and it had no fixture coverage. Linqerizer<T> needs no dedicated grammar at all; it parses as ordinary method calls.