Zig Control Flow: Mastering Logic

Zig Control Flow: Mastering Logic
In many languages (Java, JavaScript), "Control Flow" can be deceptively hidden by "Exceptions" or "Iterators." In Zig, every jump is explicit. If you see a while loop, you know exactly what the CPU is doing. If you see an if, you know exactly where the branch leads.
In this 1,500+ word guide, we will explore the "Zig Way" of writing logic. We will master the while Continue Expression, the switch Exhaustiveness, and the unique way Zig uses if as an Expression to replace the ternaries of legacy languages. We will also dive into the high-performance world of Labeled Blocks and Inline Loops that allow you to unroll logic at compile-time.
1. If-Statements: Everything is an Expression
In C and Java, if is a statement—a block of code that does something but has no "Value." In Zig, if is an expression. It can return a result.
Goodbye Ternary Operator
Zig does not have the condition ? a : b syntax. Why? Because if as an expression is more readable and less prone to errors.
If with Payload Capture
One of Zig's most powerful features is capturing data directly in the if head. This is most commonly used with Optional Types (Module 3) and Error Unions (Module 8).
2. Branch Prediction Physics: The Cost of the if
To the software, an if is a choice. To the hardware, an if is a Pipeline Stall risk.
The Branch Predictor Mirror
- The Concept: Modern CPUs (like the M4 or x86_64) use Branch Prediction to guess which way an
ifwill go before it actually executes. - The Physics: If the CPU guesses correctly, the code runs at full speed. If it guesses incorrectly (a "Branch Mispredict"), the CPU must flush its entire execution pipeline, wasting 10-20 clock cycles.
- Zig's Advantage: Zig provides the
@expectand@setRuntimeSafety(false)builtins to help the compiler generate more "Predictable" machine code, ensuring that your high-frequency branches align with the CPU's speculative execution logic.
3. While Loops: The "Continue" Expression
A while loop in Zig has a specialized syntax called the Continue Expression. This is denoted by the : after the loop condition.
The Safety Advantage
In C++, if you call continue in a while loop, you might accidentally skip the "Increment" step, leading to an Infinite Loop. In Zig, the code after the colon is guaranteed to run at the end of every iteration, matching the reliability of a for loop in other languages but with the flexibility of a conditional while.
While with Else
Did you know a while loop can have an else block?
- If the loop condition is false from the very start, the
elseblock executes. - This is useful for "Search" logic: "While looking for X... else (if not found) do Y."
3. For Loops: The Multi-Stream Engine
for loops in Zig are designed for iterating over Slices and Arrays. They are not "C-style" loops (use while for those).
Parallel Iteration
In 2026, Zig developers rarely iterate over one thing at a time. You can iterate over multiple slices of the same length simultaneously:
The 0.. Shorthand: This is an "Infinite Range." It allows you to get the current index of the loop without managing a separate var i variable.
Pointer Captures
If you want to Modify the data in the array, you must capture it as a pointer using *:
4. Switch Expressions: The Guard of Exhaustiveness
A switch in Zig is your primary defense against "Outdated Logic."
The Exhaustiveness Requirement
If you are switching on an Enum, you MUST handle every possible case. If you add a new Status.Pending to your enum but forget to update your switch block, Zig will refuse to compile your program.
Advanced Switch Patterns
- Ranges:
'a'...'z' => std.debug.print("Lowercase", .{}) - Multiple Cases:
.red, .blue => ... - Default:
else => ...(Use this sparingly; explicit cases are always safer).
5. Labeled Blocks and Breaks
Have you ever wanted to "Break" out of three nested loops at once? In other languages, you need a "Flag" variable. In Zig, you use Labels.
Labels aren't just for loops. You can label any block { ... } and use break :label value to return a value from that block. This effectively allows you to create "Anonymous Functions" or complex logic blocks that act like expressions.
6. Loop Unrolling: Defeating the Instruction Cache
Binary size is often traded for speed. Marking a loop as inline in Zig is a direct instruction to the compiler to perform Loop Unrolling.
The Cache Mirror
- The Process: a normal
forloop generates aJMPinstruction back to the start. The CPU must re-read the loop instructions from the L1 Instruction Cache. - The Physics: An
inlineloop removes theJMP. The code is laid out linearly in memory. - The Optimization: This reduces "Branch Pressure" on the hardware. However, if the loop is too large, it can overflow the L1 cache, causing a "Cache Miss" that actually slows the program down.
- The Rule: Use
inlinefor loops with a small, known number of iterations (e.g., < 16) to maximize the "Throughput" of your silicon.
Control Flow is the "Movement" of your software. By mastering the explicit jumps of Zig and the safety of exhaustive switching, you gain the ability to build logic that is 100% predictable and indestructible. You graduate from "Guessing the flow" to "Architecting Execution."
Phase 5: Execution Checklist
- Refactor your assignment logic to use
ifas an expression instead of mutablevar. - Implement a Continue Expression in a
whileloop to guarantee state increments. - Use Labeled Breaks to eliminate at least one boolean "Flag" in your nested loops.
- Identify a critical loop (e.g., a pixel filter) and test the performance of an
inline for. - Audit your
switchstatements: Ensure noelse =>fallback exists for Enum switches to maintain compile-time exhaustiveness.
Read next: Enums and Unions: The Logic of Choice →
Part of the Zig Mastery Course — engineering the flow.
