Docs/Language basics

Control flow

Branch, loop, and match on values.

On this page

Use if to branch, while and each to loop, and match to pick one of several cases. Conditions must be a bool.

If and else#

Valk
fn describe(score: int) String {
    if score >= 80 {
        return "Excellent"
    } else if score >= 50 {
        return "Passed"
    } else {
        return "Try again"
    }
}

fn main() {
    println(describe(72))            // Passed
    let score = 30
    if score < 50 : println("Low")   // one statement after a colon
    println(score > 0 ? "positive" : "zero or less")
}

if x : statement takes a single statement. cond ? a : b picks one of two values.

While#

Valk
fn main() {
    let remaining = 3
    while remaining > 0 {
        print(remaining)
        remaining--
    }
    println("")          // 321
}

The condition is checked before each round, so the body can run zero times. Use while true { ... } with break for a loop that ends in the middle.

Each#

each visits the items of a collection, with an optional index:

Valk
fn main() {
    let tasks = Array[String]{ "Build", "Test", "Ship" }
    each tasks as task, index {
        println("%{index + 1}. %task")
    }
    let stock = Map[int]{ "pen" => 3 }
    each stock as count, item : println("%item: %count") // pen: 3
    each tasks skip 1 as task : print(task + " ")        // Test Ship
    println("")
}
Collection Names after as
Array, slice, set, deque value, index
Map, HashMap value, key, index
String byte, index
Array of tuples one name per member, then index

skip n starts after the first n items; the index still counts from 0 at the first item. Removing entries from a map or set while looping over it is safe.

Count with a range#

each start .. count walks count numbers starting at start. The second number is a length, not an end:

Valk
fn main() {
    each 0 .. 3 as i : print(i)                    // 012
    println("")
    each 5 .. 3 as number, position {
        print("%number@%position ")                // 5@0 6@1 7@2
    }
    println("")
    each 0 .. 3 : print("x")                       // xxx
    println("")
}

Ranges mean the same everywhere: items[5 .. 3] takes three items starting at index 5.

Break and continue#

Valk
fn main() {
    let grid = Array[Array[int]]{ .{ 1, 2 }, .{ 3, 4 } }
    each grid as row {
        each row as cell {
            if cell == 2 : continue
            if cell == 4 : break 2
            print(cell)
        }
    }
    println("")   // 13
}

break leaves the loop, continue starts its next round. A number leaves that many loops: break 2 also ends the outer loop.

Match a set of alternatives#

match compares a value against cases. With : Type it produces a value:

Valk
enum Status { queued, running, finished }

fn label(status: Status) String {
    return match status : String {
        .queued => "Waiting"
        .running => "In progress"
        .finished => "Done"
    }
}

fn main() {
    println(label(.running))  // In progress
    let status = Status.finished
    match status {
        .finished => println("All done")
        default => println("Still busy")
    }
}

Every case of a value match must produce the type, or leave with return, throw, break, continue or panic. Covering every enum item (or true and false) makes default unnecessary.

Match patterns#

Valk
fn size(n: int) String {
    return match n : String {
        0 => "none"
        1, 2, 3 => "few"           // several values
        4 .. 6 => "some"           // range: 4 to 9
        _ if n < 0 => "negative"   // any value, with a guard
        default => "many"
    }
}

fn command(input: String) String {
    return match input : String {
        "start", "run" => "starting"
        "stop" => "stopping"
        default => "unknown"
    }
}

fn main() {
    println(size(2))         // few
    println(size(-5))        // negative
    println(command("run"))  // starting
}
Pattern Matches
5, "text", 'a', .item One value
1, 2, 3 Any listed value
'a' .. 26 An integer range (start, count)
pattern if condition Only when the guard is true
_ Anything
String as s A type of a tagged union, bound to s
null A missing value
default Everything not matched before

Compute a value in a block#

<{ ... } runs several statements and return gives the block's value:

Valk
fn main() {
    let total = <{
        let subtotal = 40
        let delivery = 5
        return subtotal + delivery
    }
    println(total)  // 45
    let port = "abc".to(int) !? <{
        println("Invalid port, using 8080")
        return 8080
    }
    println(port)
}

This is handy as an error fallback that needs more than one step.