Control Flow in Vale
Learn conditionals, if-expressions, while loops, and foreach iteration in Vale with practical Docker-ready examples
Control flow is how a program decides what to do and how many times to do it. As an imperative systems language, Vale offers the structured control-flow constructs you would expect — if/else, while, and foreach — but with a few touches that set it apart from C++ or Rust.
Two things stand out right away. First, Vale conditions take no parentheses: you write if x < 10 { ... }, not if (x < 10). Second, the boolean connectives are spelled out as the words and, or, and not rather than &&, ||, and !. Vale also treats if as an expression — every if/else can yield a value — which removes the need for a separate ternary operator.
In this tutorial you will write conditionals, use if as an expression to compute a value, repeat work with while loops, and iterate over collections with foreach. Every example is a complete program you can compile and run with Docker.
Conditionals: if, else if, else
The if statement runs a block when its condition is true. Chain alternatives with else if, and provide a fallback with else. Conditions are combined with the keyword operators and, or, and not, and Vale’s mod operator gives the remainder (handy for divisibility tests).
Create a file named control_flow_if.vale:
import stdlib.*;
exported func main() {
temperature = 18;
// Basic if / else if / else chain
if temperature < 0 {
println("Freezing");
} else if temperature < 15 {
println("Cold");
} else if temperature < 25 {
println("Comfortable");
} else {
println("Hot");
}
// Logical operators: and, or, not
hour = 9;
isWeekend = false;
if hour >= 9 and hour < 17 and not isWeekend {
println("Working hours");
}
// The mod operator tests divisibility
number = 12;
if number mod 2 == 0 {
println("12 is even");
} else {
println("12 is odd");
}
}
temperature is 18, so the first two conditions fail and the temperature < 25 branch wins. The working-hours check passes because all three sub-conditions hold, and 12 mod 2 is 0, so the number is reported as even.
if as an Expression
In Vale, if is not just a statement — it is an expression that evaluates to the value of whichever block runs. The final expression in a block (written without a trailing semicolon) becomes that block’s value. This is how Vale does what other languages express with a ternary ? : operator.
Create a file named control_flow_expr.vale:
import stdlib.*;
exported func main() {
n = 7;
m = 12;
// if is an expression: the chosen block's final value is assigned
larger =
if n > m {
n
} else {
m
};
println("The larger value is: " + larger);
// A block can do work before yielding its final value
label =
if n mod 2 == 0 {
"even"
} else {
"odd"
};
println(n + " is " + label);
}
Because n (7) is not greater than m (12), the else branch yields 12, which is bound to larger. The second if-expression yields the string "odd" since 7 mod 2 is 1. Notice the values inside the branches — n, m, "even", "odd" — have no semicolon: that is what marks them as the block’s result.
Repeating Work: the while Loop
A while loop repeats its body as long as the condition stays true. Local variables in Vale are reassigned with the set keyword — plain assignment (=) introduces a new binding, while set updates an existing one. Forgetting set is the most common beginner mistake when writing loops.
Create a file named control_flow_while.vale:
import stdlib.*;
exported func main() {
// Count from 1 up to 5
i = 1;
while i <= 5 {
println("Count: " + i);
set i = i + 1;
}
// Accumulate a running total of 1 through 10
total = 0;
n = 1;
while n <= 10 {
set total = total + n;
set n = n + 1;
}
println("Sum of 1..10 is: " + total);
}
The first loop prints Count: 1 through Count: 5, advancing i with set i = i + 1 each pass. The second loop adds each value of n into total; after n passes 10 the loop ends and the sum, 55, is printed. Without the set n = n + 1 line the condition would never change and the loop would run forever — every while body must make progress toward its exit condition.
Iterating Over Collections: foreach
When you need to walk through a collection rather than count, use foreach. Vale’s foreach iterates over an array, and you can either take each element directly or use .entries() to get an index/value pair. The & borrows the array for reading without taking ownership of it.
Create a file named control_flow_foreach.vale:
import stdlib.*;
exported func main() {
// Build a 5-element array of even numbers: [0, 2, 4, 6, 8]
// The initializer {_ * 2} receives each index as `_`
evens = [](5, {_ * 2});
// Iterate over the elements by reference
foreach value in &evens {
println("Value: " + value);
}
// Iterate with both the index and the value
foreach [ix, value] in evens.entries() {
println("Index " + ix + " holds " + value);
}
}
The array constructor [](5, {_ * 2}) builds five elements by calling the closure {_ * 2} with each index 0..4, producing [0, 2, 4, 6, 8]. The first foreach prints each value; the second destructures [ix, value] from .entries() to print both the position and the contents.
Putting It Together: FizzBuzz
FizzBuzz combines a while loop with an if/else if/else chain — a compact exercise in control flow. Order matters: the divisible-by-15 case must be checked first, otherwise a multiple of 15 would be caught by the mod 3 branch before the combined case is ever reached.
Create a file named control_flow_fizzbuzz.vale:
import stdlib.*;
exported func main() {
i = 1;
while i <= 15 {
if i mod 15 == 0 {
println("FizzBuzz");
} else if i mod 3 == 0 {
println("Fizz");
} else if i mod 5 == 0 {
println("Buzz");
} else {
println(i);
}
set i = i + 1;
}
}
For each number from 1 to 15, the program prints Fizz for multiples of 3, Buzz for multiples of 5, FizzBuzz for multiples of both, and the number itself otherwise.
Running with Docker
These examples use the custom codearchaeology/vale:0.2 image, which bundles the Vale compiler (valec), a JDK for the Scala frontend, and clang for linking. Pull the image once, then compile and run each file. Each valec build produces a fresh ./build/main binary.
| |
Note: valec prints verbose build progress (frontend, backend, and linker stages) to stdout before your program runs. Your program’s output appears at the end; any compiler warnings from Vale’s built-in C support files are harmless.
Expected Output
control_flow_if.vale:
Comfortable
Working hours
12 is even
control_flow_expr.vale:
The larger value is: 12
7 is odd
control_flow_while.vale:
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5
Sum of 1..10 is: 55
control_flow_foreach.vale:
Value: 0
Value: 2
Value: 4
Value: 6
Value: 8
Index 0 holds 0
Index 1 holds 2
Index 2 holds 4
Index 3 holds 6
Index 4 holds 8
control_flow_fizzbuzz.vale:
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
Key Concepts
- No parentheses on conditions — Vale writes
if x < 10 { ... }andwhile x < 10 { ... }, omitting the parentheses that C++ and Rust require around the condition. - Word operators — boolean logic uses the keywords
and,or, andnotinstead of&&,||, and!. Themodoperator returns the remainder of integer division. ifis an expression — everyif/elseevaluates to a value, so you assign the result directly (grade = if ... { ... } else { ... };) instead of reaching for a ternary operator.- Blocks yield their last expression — the final expression in a block, written without a trailing semicolon, becomes the block’s value; everything before it runs as ordinary statements.
=declares,setreassigns — a plain=introduces a new binding, while updating an existing variable inside a loop requiresset. Mixing these up is the most common loop bug in Vale.whilefor counting,foreachfor collections — usewhilewith aset-updated counter for indefinite repetition, andforeach value in &collection(or.entries()for index/value pairs) to walk arrays.- Order your conditions deliberately — in an
else ifchain only the first matching branch runs, so place the most specific case (like FizzBuzz’s divisible-by-15 test) before the more general ones.
Running Today
All examples can be run using Docker:
docker pull codearchaeology/vale:0.2
Comments
Loading comments...
Leave a Comment