Luce
Luce BaseSourceLuciaOS

8. Control flow

8.1 if, elif, else#

if n < 0:
    sign = -1
elif n == 0:
    sign = 0
else:
    sign = 1

8.2 Conditional binding#

if let user = find(users, id):
    greet(user)
else:
    print("no such user")

while let line = reader.next():
    process(line)

if let and while let bind the payload of a T? when it is present.

8.3 while, for#

for i in 0..<10:
    print(i)
for name in names:
    print(name)
for (index, name) in names.indexed():
    print(f"{index}: {name}")
for (key, value) in ages:
    print(f"{key} is {value}")
for character in "héllo":
    print(character)

for iterates a range, a list, a set, a map (as key-value tuples), a str (as one-scalar strings), bytes (as ints 0 to 255), or any value of a type that declares Iterable (§13.3). break and continue apply to the innermost loop; a loop may be labelled, outer: for ..., and break outer leaves it. Structurally mutating a collection while a for runs over it traps.

8.4 match#

match shape:
    .circle(radius):
        return 3.14159 * radius ** 2
    .rectangle(width, height):
        return width * height
    .empty:
        return 0.0

let word = match n:
    0 => "zero"
    1..<10 => "digit"
    _ if n < 0 => "negative"
    _ => "many"

match is exhaustive over an enum's cases, and over anything else with _ or a name. Patterns are enum cases with bound payloads, literals, ranges, tuples of patterns, none, a name, which binds the whole value or the payload of an optional that is present, and _, each with an optional guard. The statement form has suites; the expression form has => arms of one type.

A match expression over a tuple or over bytes reads its subject in every arm, so the subject is a name, a literal, or a tuple of those, and its arms bind no names; bind the value or use the statement form otherwise.

8.5 return, defer-less cleanup, with#

return leaves the function with a value. There is no defer. A resource is closed by with:

with files.open(path) as file:
    for line in file.lines():
        process(line)

with expression as name: binds the value, runs the suite, and calls name.close() when the suite ends, however it ends: normally, by return, by break, or by a failure passing through. Any value whose type has a close() method returning unit may be used; a Base handle (§16.4) always has one. with may bind several, with a as x, b as y:, closed in reverse order.