Grasm v1.0.0 Get started

Learn

Errors

A function that can fail says so in its type. Ignoring that is a compile error, not a runtime one.

Fallible types

type MathError = | DivByZero

fn safe_div(a: i64, b: i64) -> i64 ! MathError {
    if b == 0 {
        fail(DivByZero)
    }
    a / b
}

i64 ! MathError is an i64 or a MathError. Three ways to open it:

match safe_div(10, 0) {                 // handle both halves
    Ok(v) -> print("{v}")
    Err(e) -> print("caught: {e}")
}

let v = safe_div(10, 2) ?? 0 - 1        // take a default; the right side is lazy

fn caller() -> i64 ! MathError {
    let v = try safe_div(10, 2)         // propagate, and say so in the type
    v * 2
}

What you cannot do is nothing. let _ = risky() is refused too — a binding being unnamed says nothing about whether its failure was considered.

Panics

A panic is for a bug, not for a condition: an index out of range, a division by zero, an expect on None. It prints a message and exits 101 in every engine. Whether a stack trace follows depends on how the program was run, and the specification says which engines print one.

No null

Something that may be absent is an Option[T], and the compiler makes you open it before you can use what is inside.

let found: Option[i64] = m.get("k")
print("{found ?? 0}")