Control Flow

Conditionals, loops, and pattern matching in Sounio

Control Flow

Sounio provides familiar control flow constructs with some powerful additions.

Conditionals

If Expressions

let max = if a > b { a } else { b }
if temperature > 30.0 {
    print("It's hot!")
} else if temperature > 20.0 {
    print("It's pleasant")
} else {
    print("It's cold")
}

Confidence Gates

For epistemic types, you can gate on confidence:

let measurement: Knowledge<f64> = sensor.read()

if measurement.confidence > 0.95 {
    // High confidence - proceed with decision
    activate_system(measurement.value)
} else {
    // Low confidence - request more data
    perform IO::warn("Insufficient confidence")
}

Loops

While Loops

var count = 0
while count < 10 {
    print(count.to_string())
    count = count + 1
}

For Loops

for i in 0..10 {
    print(i.to_string())
}

for item in collection {
    process(item)
}

Loop with Break

var result = 0
loop {
    result = result + 1
    if result > 100 {
        break
    }
}

Continue

for i in 0..10 {
    if i % 2 == 0 {
        continue  // Skip even numbers
    }
    print(i.to_string())
}

Pattern Matching

Match Expressions

let result = match value {
    0 => "zero",
    1 => "one",
    2..=9 => "single digit",
    _ => "large number",
}

Matching Enums

enum Status {
    Success(i32),
    Error(String),
    Pending,
}

let message = match status {
    Status::Success(code) => "Success: " + code.to_string(),
    Status::Error(msg) => "Error: " + msg,
    Status::Pending => "Still waiting...",
}

Matching with Guards

match point {
    (x, y) if x == y => print("On diagonal"),
    (x, 0) => print("On x-axis at " + x.to_string()),
    (0, y) => print("On y-axis at " + y.to_string()),
    (x, y) => print("At (" + x.to_string() + ", " + y.to_string() + ")"),
}

Matching Knowledge Types

match measurement {
    m if m.confidence > 0.99 => "Very confident",
    m if m.confidence > 0.90 => "Confident",
    m if m.confidence > 0.50 => "Uncertain",
    _ => "Unreliable",
}

Early Returns

fn find_user(id: i32) -> Option<User> with IO {
    if id < 0 {
        return None
    }

    let user = database.lookup(id)
    Some(user)
}

Error Handling

Result Type

fn parse_number(s: String) -> Result<i32, ParseError> {
    // ...
}

match parse_number("42") {
    Ok(n) => print("Got: " + n.to_string()),
    Err(e) => print("Error: " + e.message),
}

The ? Operator

fn process_file(path: String) -> Result<Data, Error> with IO {
    let content = read_file(path)?  // Returns early on error
    let parsed = parse(content)?
    Ok(transform(parsed))
}

What’s Next?