Cinder by Example

Cinder is small programming language for low-level development.

Optionals and Errors

Cinder has no NULL in safe code. Missing values use ?T, and failure uses

!T.

Optionals

?T is either a T value or none.

use "std/io.cnd";

fn maybe_name(id: i32) -> ?[]u8 {
    if id == 0 {
        return none;
    }
    return "cinder";
}

fn main() -> i32 {
    let a = maybe_name(0);
    let b = maybe_name(7);
    let x = a else { println("a is none"); return 0; };
    println(x);
    let y = b else { return 2; };
    println(y);
    return 0;
}
$ ./optionals
a is none

else bindings

let x = v else { ... }; unwraps the optional. If it is none, the block

runs and the binding fails; the block must leave the function (return, break,

or panic).

use "std/io.cnd";

fn show(v: ?i32) -> i32 {
    let x = v else { return 0; };
    print(&x, .I32);
    putchar(10);
    return 1;
}

fn main() -> i32 {
    show(42);
    show(none);
    return 0;
}
$ ./else_bind
42

Error types

!T is either a T value or an error. Errors are usually enum variants.

use "std/io.cnd";

enum Err {
    DivisionByZero;
}

fn safe_div(a: i32, b: i32) !i32 {
    if b == 0 {
        return Err.DivisionByZero;
    }
    return a / b;
}

fn main() -> i32 {
    let r = safe_div(10, 2) else {
        println("error");
        return 1;
    };
    print(&r, .I32);
    putchar(10);

    let bad = safe_div(1, 0) else {
        println("division by zero");
        return 0;
    };
    return 2;   // unreachable
}
$ ./errors
5
division by zero

The ? operator

Inside a function that returns an error type, ? propagates the error.

use "std/io.cnd";

enum Err {
    DivideByZero;
    Negative;
}

fn checked(a: i32, b: i32) !i32 {
    if b == 0 { return Err.DivideByZero; }
    if a < 0 { return Err.Negative; }
    return a / b;
}

fn half(a: i32) !i32 {
    let q = checked(a, 2)?;
    return q;
}

fn main() -> i32 {
    let h = half(10) else { return 1; };
    print(&h, .I32);
    putchar(10);

    let bad = half(-4) else { println("error propagated"); return 0; };
    return 2;   // unreachable
}
$ ./propagate
5
error propagated

Optionals in the standard library

Lookups return ?T: readbyte() -> ?u8, vecget() -> ?u8,

strindexof() -> ?usize. Parse helpers return ?T too:

use "std/io.cnd";
use "std/core/str.cnd";

fn main() -> i32 {
    let n = str_parse_i64("1234") else { return 1; };
    print(&n, .I64);
    putchar(10);
    return 0;
}
$ ./parse
1234