"For" and "with" expressions
"For" loops
The for syntax is designed for iterating over collections.
It can be void as above,
or it can be used to map over a collection.
It can even produce a different type of collection.
It can be written on one line by using a ;.
Desugaring for loops
for is actually just syntax for calling a function
for-loop and passing it a lambda.
(That is usually implemented using a loop
or by delegating to another for-loop function.)
"For-break" loops
Sometimes you want to stop the loop early.
For that, use break and continue
like in a loop.
This desugars to calling a function
for-break nat(xs nat[], f-body nat break-or-continue mut(x nat), f-else nat mut()).
The break and continue keywords
desugar into constructing break-or-continue values.
That type is declared in misc.
Like in a loop, break can take a value.
Since the break isn't guaranteed to be reached
(since the collection could run out first), the result is wrapped in an option.
You could avoid that by providing an else block to provide a value
if break isn't reached.
The above calls a function that works like
for-break nat(xs nat[], f-body nat break-or-continue mut(x nat), f-else nat mut()).
"With" expressions
A related expression is with.
Technically, this behaves exactly like for
except that the function it calls is named with-block
instead of for-loop.
However, using with instead of for
implies that the body will usually execute only once.
It's not meant for loops.
One example use is to build a collection.
build returns a type called build-options
which is used as the argument to with-block.
The signature works like with-block string(a build-options, f void mut(out string-builder)).