Bbetlang

Functions

Declaring functions, returns, methods, generics, and function values.

Functions are declared with finna (as in “finna do a thing”) and hand results back with bet.

Declaring a function

finna add(a: int, b: int) -> int {   // finna = fn, bet = return
    bet a + b
}

The return arrow and type are omitted when a function returns nothing (void).

Returns and multi-value returns

bet returns zero or more values: bet, bet x, or bet a, b. A function that returns several values declares a tuple return type, destructured at the call site.

finna divmod(a: int, b: int) -> (int, int) {
    bet a / b, a % b
}
lowkey q, r = divmod(17, 5)   // destructure

Errors ride along as the last value of a multi-value return ((T, yikes)); see Features.

Methods (Go-style receivers)

A function with a receiver attaches behavior to a drip (struct):

drip Counter { flex n: int }

finna (c: Counter) bump(by: int) -> int {
    bet c.n + by
}

finna main() {
    lowkey c = Counter{ n: 10 }
    spill.it(c.bump(5))   // 15
}

Generics

Type parameters go in [...] on functions and structs, resolved by ahead-of-time monomorphization: each instantiation compiles to its own concrete code, with no runtime type info.

finna pickFirst[T](a: T, b: T) -> T { bet a }
spill.it(pickFirst[int](7, 9))       // 7
spill.it(pickFirst[str]("a", "b"))   // a

Function values

Functions are first-class citizens here: pass one by name, stash it in a variable, hang it off a struct field. The type is spelled with finna. Function-pointer fields are the whole dispatch story in v1, so no interfaces or traits yet, but you can get surprisingly far with a struct full of finnas.

finna dub(x: int) -> int { bet x * 2 }

finna apply(f: finna(int) -> int, x: int) -> int {
    bet f(x)
}

lowkey g: finna(int) -> int = dub
spill.it(apply(g, 21))   // 42