Grasm v1.0.0 Get started

Learn

A tour of the language

Everything you need to read Grasm, in order.

Bindings

let binds; var binds something you may reassign. Types are inferred and may be written.

let n = 1 + 2
let x: f64 = 2          // an integer literal becomes a float where one is wanted
var total = 0
total = total + n

Types

KindWrittenExample
Primitivesi64 f64 bool str bytes ()let ok: bool = true
List[T][1, 2, 3]
MapMap[K, V]{ "a": 1 }
Tuple(A, B)(1, "a")
Rangerange0..10, 0..=10
Structtype P = { x: i64 }P{ x: 1 }
Sumtype C = | Red | GreenRed
OptionOption[T]Some(1), None
FallibleT ! Ei64 ! MathError
Functionfn(A) -> B|n| n + 1
Referenceref Tref(0)

There is no null. Something that may be absent is an Option, and the compiler makes you open it.

Control

let label = if n > 0 { "positive" } else { "not" }

match value {
    Some(v) -> print("{v}")
    None    -> print("nothing")
}

for i in 0..3 { }
for v in [1, 2, 3] { }
while more { }

if and match are expressions. A match must cover its subject, and the compiler says which case is missing.

Functions and closures

fn twice(n: i64) -> i64 {
    n * 2
}

let f = |n| n + 1                 // a closure captures by value, at creation
let g: fn(i64) -> i64 = twice     // a function is a value

[1, 2, 3].map(twice)
3 |> twice                        // the same call, written the other way

Generics

type Stack[T] = { items: [T] }

fn same[T](v: T) -> T {
    v
}

Generics are monomorphised: one compiled copy per member of the family. The one thing this cannot do is polymorphic recursion, and it is refused by name rather than miscompiled.

Parameters

ModeMeans
fn f(x: T)A borrow. The caller keeps it.
fn f(own x: T)Ownership moves in. Scalars copy, so the caller keeps those.
fn f(inout x: T)An exclusive mutable borrow; writes land in the caller's value.

Next

Effects and capabilities

What a function may do, and how a package is held to it.

Ownership tiers

Four ways to own a value, chosen per value.