Control flow#
Two branch forms, six loop forms, and a bounded loop you will not find in other languages.
if / else if / else#
Conditions take no parentheses. Braces are mandatory even for one statement.
-- `if` / `else if` / `else`. Conditions take no parentheses.
task describe(power: int) -> word {
if power > 9000 {
give back "over nine thousand"
} else if power > 5000 {
give back "high"
} else if power > 1000 {
give back "moderate"
} else {
give back "low"
}
}
task main() -> void {
say describe(9001)
say describe(6000)
say describe(2000)
say describe(10)
}
over nine thousand
high
moderate
low
else if chains to any depth. Internally V3 flattens these rather than nesting them, which is one of the architectural fixes that made the self-hosted compiler possible.
when#
when matches a subject against literal arms. _ is the catch-all.
-- `when` matches a subject against literal arms. `_` is the catch-all.
-- Each arm takes one statement; use a block to run several.
task main() -> void {
pilot code: int = 2
when code {
1 -> say "launch"
2 -> {
say "hold"
say "await orders"
}
3 -> say "abort"
_ -> say "unknown"
}
pilot phase: word = "sortie"
when phase {
"briefing" -> say "in the briefing room"
"sortie" -> say "in the air"
_ -> say "elsewhere"
}
}
hold
await orders
in the air
Rules:
- Each arm is
pattern -> statement. One statement — wrap several in a block. - Arms are separated by nothing at all; newlines are enough.
- The subject may be
int,word,boolornum. - Arm patterns are expressions compared for equality, not patterns. There is no destructuring, no binding, no guards, no ranges.
- Exhaustiveness is not checked. Without a
_arm and with no match, nothing runs. whenis a statement, not an expression. It cannot appear on the right of=or insidegive back.
To produce a value from a match, assign inside the arms:
Illustrative snippet; not independently verified. Use the badged executable examples for tested programs.
task main() -> void {
pilot code: int = 2
pilot mut label: word = ""
when code {
1 -> label = "launch"
2 -> label = "hold"
_ -> label = "unknown"
}
say label
}Destructuring arms — BETA::Soldier { position } -> engage_at(position) — need variants, which V3 does not have. So does check over maybe / result, and check route. See Not in V3.
Loops#
The listing shows the counted loop, the condition loop and the bounded training arc. for each, the C-style for and while have their own sections below.
-- Three of V3's loop forms: a counted loop, a condition loop,
-- and the bounded `training arc`.
task main() -> void {
-- repeat N times
pilot mut total: int = 0
repeat 5 times {
total += 2
}
say word_from_int(total)
-- repeat until CONDITION (tested before each pass)
pilot mut countdown: int = 3
repeat until countdown == 0 {
say word_from_int(countdown)
countdown -= 1
}
-- break and continue work in every loop form
pilot mut seen: int = 0
repeat 10 times {
seen += 1
if seen == 3 { continue }
if seen == 6 { break }
}
say word_from_int(seen)
}
10
3
2
1
6
repeat N times#
Illustrative snippet; not independently verified. Use the badged executable examples for tested programs.
repeat COUNT times { body }COUNT is any int expression, evaluated once before the loop. Add with NAME to get a counter that starts at 0: repeat COUNT times with i { }.
Illustrative snippet; not independently verified. Use the badged executable examples for tested programs.
pilot mut i: int = 0
repeat array_len(items) times {
say array_get(items, i)
i += 1
}repeat until#
Illustrative snippet; not independently verified. Use the badged executable examples for tested programs.
repeat until CONDITION { body }The condition is tested before each pass, so the body may run zero times. Note the sense: the loop continues while the condition is false.
training arc#
Illustrative snippet; not independently verified. Use the badged executable examples for tested programs.
training arc until CONDITION max N sessions { body }A loop with a compulsory iteration cap. It stops when the condition becomes true or when the cap is reached — whichever comes first — so it cannot spin forever.
-- `training arc` is a loop with a mandatory session cap.
-- It stops when the condition becomes true OR when the cap is hit,
-- so it cannot spin forever.
task main() -> void {
pilot mut power: int = 0
training arc until power >= 100 max 8 sessions {
power += 20
}
say word_from_int(power)
-- The cap wins when the condition is never reachable.
pilot mut stuck: int = 0
training arc until stuck > 1000 max 4 sessions {
stuck += 1
}
say word_from_int(stuck)
}
100
4
It lowers to roughly:
int64_t sessions = 0;
while (!(CONDITION) && sessions < N) {
body;
sessions++;
}This makes it genuinely useful for bounded numeric search, where you want a hard guarantee of termination:
-- A slightly larger program: integer square root by bisection, driven by
-- a `training arc` so the loop is provably bounded.
shape Bounds {
lo: int
hi: int
}
task isqrt(target: int) -> int {
if target < 2 { give back target }
pilot mut b: Bounds = Bounds { lo: 1, hi: target }
training arc until b.lo >= b.hi max 64 sessions {
pilot mid: int = (b.lo + b.hi + 1) / 2
if mid * mid > target {
b.hi = mid - 1
} else {
b.lo = mid
}
}
give back b.lo
}
task main() -> void {
say word_from_int(isqrt(0))
say word_from_int(isqrt(1))
say word_from_int(isqrt(15))
say word_from_int(isqrt(16))
say word_from_int(isqrt(17))
say word_from_int(isqrt(1000000))
}
0
1
3
4
4
1000
The with growth variant — which makes the compiler verify that the body actually mutates the condition's subject — is V4. Plain training arc is fully supported.
break and continue#
Both work in every loop form.
Illustrative snippet; not independently verified. Use the badged executable examples for tested programs.
repeat 10 times {
if should_skip { continue }
if should_stop { break }
process()
}Bare blocks#
A { ... } on its own is a statement. It groups code but does not create a new scope for bindings — a pilot declared inside remains visible afterwards.
Illustrative snippet; not independently verified. Use the badged executable examples for tested programs.
task main() -> void {
pilot x: int = 1
{
say word_from_int(x)
}
}eventually#
eventually { ... } is the cleanup block. Its V3 behaviour differs sharply from the specification.
-- `eventually { ... }` marks a cleanup block.
--
-- IMPORTANT V3 caveat: V3 emits the block INLINE at the point it is
-- written. It is not deferred to the end of scope and it does not run
-- on `give back`, `break` or `panic`. Place it where you want it to run.
task main() -> void {
say "engaging"
eventually {
say "cleanup"
}
say "disengaged"
}
engaging
cleanup
disengaged
V3 emits the block inline, where you wrote it. It is not deferred to the end of scope, it does not run in LIFO order with other eventually blocks, and it does not run on give back, break or panic. Treat it as a labelled section, not as defer. True deferred semantics are V4.
for each, ranges and counting loops#
for each NAME in LIST { } visits each element of a list. The same form walks a range of ints: a..b excludes b, a..=b includes it, and step sets the distance between values. repeat N times with NAME { } names the counter of a counted loop, starting at 0. The C-style for (pilot i = 0; i < n; i += 1) { } is also accepted. In every form the loop variable exists only inside the body.
-- Counting loops. A range a..b stops before b; a..=b includes b.
task main() {
for each i in 1..4 {
say "range {i}"
}
for each i in 1..=3 {
say "inclusive {i}"
}
for each i in 0..10 step 4 {
say "step {i}"
}
repeat 2 times with pass {
say "pass {pass}"
}
for (pilot i = 3; i > 0; i -= 1) {
say "countdown {i}"
}
}
range 1
range 2
range 3
inclusive 1
inclusive 2
inclusive 3
step 0
step 4
step 8
pass 0
pass 1
countdown 3
countdown 2
countdown 1
A word is not a list: for each c in "abc" is a type error.
while#
while CONDITION { } runs as long as the condition is true, testing before each pass. repeat while CONDITION { } is the same loop. while is a reserved word.
-- `while` runs as long as its condition is true: the opposite of `repeat until`.
task main() {
pilot fuel = 3
while fuel > 0 {
say "fuel {fuel}"
fuel -= 1
}
pilot laps = 0
repeat while laps < 2 {
laps += 1
}
say "laps {laps}"
}
fuel 3
fuel 2
fuel 1
laps 2
Summary of what is missing#
| Construct | Status |
|---|---|
for each (i, x) in list.enumerate() | V4 |
check over maybe / result | V4 |
check route | V4 |
when with destructuring or guards | V4 |
when in expression position | V4 |
training arc ... with growth | V4 |
xm3 { a || b } and all squadron concurrency | V4 |
prob[0.3] chance { }, prob_when | V4 |
isekai { } bringing back { } | V4 |
eventually if cond { } | V4 |
True deferred eventually | V4 |