luxc 0.8.3

A small teaching language that runs anywhere and transpiles to Rust, Swift, and Go
Documentation
// lux has no null. A value that might be missing has type Option<T>:
// it is either some(value) or none. A value that might fail has type
// Result<T, E>: either ok(value) or err(reason). You can't forget the missing
// or failing case, because match makes you handle it.

let primes = [2, 3, 5, 7, 11]

// Option: search returns some(index) on a hit, none on a miss. The return type
// Option<int> is what fixes what `none` means here.
func indexOf(items: [int], target: int) -> Option<int> {
    var i = 0
    for item in items {
        if item == target {
            return some(i)
        }
        i += 1
    }
    return none
}

match indexOf(primes, 5) {
    some(let idx) => print("5 is at index", idx)
    none          => print("5 is not in the list")
}
match indexOf(primes, 4) {
    some(let idx) => print("4 is at index", idx)
    none          => print("4 is not in the list")
}

// Result: when the failure has something to say, carry a reason in err.
func half(n: int) -> Result<int, string> {
    if n % 2 == 0 {
        return ok(n / 2)
    }
    return err("not even")
}

for n in [8, 7] {
    match half(n) {
        ok(let h)  => print(n, "halves to", h)
        err(let e) => print(n, "can't:", e)
    }
}

// An Option can sit inside your own types. A var of an Option type starts as
// none, the natural "nothing yet".
struct Contact {
    name: string
    email: Option<string>
}

let withEmail = Contact(name: "Ada", email: some("ada@example.com"))
let noEmail = Contact(name: "Grace", email: none)

for who in [withEmail, noEmail] {
    match who.email {
        some(let e) => print(who.name, "<" + e + ">")
        none        => print(who.name, "(no email on file)")
    }
}