Statements

Statements are run as soon as they are encountered at runtime. They do not evaluate to a value.

= (assignment)

An assignment statement gives a name to a value inside the current scope.

Pattern matching in assignments

You can use pattern matching in assignments to do things like destructuring:

(x, y) = (1.1, 2.2)

The pattern you use here must be exhaustive. For example, the following would give an exhaustiveness error because it doesn't specify what to do if list.first() returned an Err instead of Ok:

Ok(item) = list.first()

If you can't write an exhaustive pattern-match, you can use match instead of an assignment.

Assignment Order

Assignments inside expressions can only reference names that were assigned earlier in scope. For example, this would be an error:

foo({
    y = z + 1
    z = 5

    z + 1
})

However, at the top level of a module, assignments can reference each other regardless of declaration order:

x = y + 1
y = 5

Assignment Cycles

Top-level assignments can only mutually reference each other if they are all assigning to functions. This gives an error at compile time:

x = y + 1
y = x + 1

(If it did not give an error at compile time, it would either crash or loop infinitely at runtime.)

In contrast, this gives no error because all the assignments in the cycle are assigning to functions:

x = |arg| if arg >= 1 { y(arg + 1) } else { 0 }
y = |arg| if arg <= 9 { x(arg + 1) } else { 0 }

Reassignment

Reassigning to an existing name is only allowed when the name was declared with var. This is allowed:

var $foo = 0
$foo = 1

However, this gives a shadowing error:

foo = 0
foo = 1

import

The import statement imports a type into scope from a type module.

import with exposing

TODO

Renaming Imports with as

TODO

Importing non-Roc files

TODO

dbg

TODO

expect

TODO

return

The return statement immediately exits a function, returning the given value.

my_func = |arg| {
    if arg == 0 {
        return 0

        # This line will never be reached.
    }

    arg - 1
}

break

(This has not been implemented yet. It will exit a for or while loop.)

continue

(This has not been implemented yet. It will continue to the next iteration of a for or while loop.)

crash

A crash statement crashes the running application. All code following the crash becomes unreachable and will not be executed.

if some_condition {
    crash "There is no way this program could possibly continue."
}

# This line will never be reached if `some_condition` was `True`

What happens after a crash is determined by the platform. Some may gracefully recover and have some way of continuing the process, but others may terminate the process immediately.

Block Statements

A block statement is a group of statements which has its own scope, so anything assigned in it can't be accessed outsdie the block.

It's different from a block expression in that a block statement does not have an expression at the end. A common block statement is one that does an early return in a conditional branch:

if foo {
    …
} else {
    bar = …

    return bar
}

Having a single statement in a block expression is allowed:

if foo {
    …
} else {
    return bar
}