A path in a forest splitting into two directions between trees. Photo · Jens Lelie / Unsplash
Two roads diverged in a wood. The chef takes one, based on a single yes/no answer. Repeat a few billion times and you have software.

You can now compute. You cannot yet decide. Right now, every C program you've written runs straight through, top to bottom, doing exactly the same thing every time. Real software branches. It says: if the user clicked here, then this; otherwise, that. If the file exists, open it; otherwise, error out. If the network is up, send the request; otherwise, queue it.

This is the conceptual atom of every algorithm ever written. Strip away the syntax of the most baroque language, and what's left is some assembly of if-this-then-that-else-the-other, repeated. The chef has exactly one tool for this: a conditional jump. Everything else is built from there.

The shape of if

if (condition) {
    // runs only if condition is true
} else {
    // runs only if condition is false
}

The condition is anything that produces a number. C's rule is simple: 0 is false; anything else is true. Including 1, -1, 42, 0.0001, the address of any allocated object, and the result of any comparison. The "boolean" idea is conceptual; under the hood it's just integer arithmetic.

The else branch is optional. if (x > 0) { ... } with nothing after it is a complete construct: do the body if true, do nothing if false.

A real example

#include <stdio.h>

int main(void) {
    int score = 73;

    if (score >= 90) {
        printf("A\n");
    } else if (score >= 75) {
        printf("B\n");
    } else if (score >= 60) {
        printf("C\n");
    } else {
        printf("F\n");
    }
    return 0;
}

This prints C. The chef checks each condition top to bottom. The first one that's true wins; the rest are skipped. else if is just convention — there's no special keyword. It's literally else followed by if, and most C codebases write it as one line for readability.

What the chef actually sees

Remember Week 4 — the chef only knows fetch/decode/execute, with a small vocabulary of jumps and comparisons. Here's roughly what the assembly looks like for one of those ifs:

// if (score >= 90) { ...A... } else { ...B... }

        cmp   w0, #90      // compare score to 90
        b.lt  .else_branch  // if less, jump to else
        // ... A code here ...
        b     .end           // skip the else
.else_branch:
        // ... B code here ...
.end:
        // program continues here

One cmp (compare). One b.lt (branch-if-less-than). One unconditional b (branch). That's it. Every if/else in every program in every language compiles down to roughly this shape. Once you've seen it, you can never quite unsee it.

condition? score >= 90 then-branch else-branch continue true false

The truth tables you should memorise

Boolean logic has rules. Three main operators (&&, ||, !) and a small finite truth table for each. Memorising these saves you time forever.

ABA && BA || B!A
truetruetruetruefalse
truefalsefalsetruefalse
falsetruefalsetruetrue
falsefalsefalsefalsetrue

The takeaways:

And the duality you'll find yourself using: De Morgan's Law. !(A && B) is the same as !A || !B. !(A || B) is the same as !A && !B. Whenever a long, complex boolean expression feels wrong, try negating it and using De Morgan to flip the whole thing inside out — sometimes the result is dramatically clearer.

The ternary — condition ? a : b

C has a tiny, useful shorthand for "pick one of two values based on a condition":

int larger = (a > b) ? a : b;

Read it: "if a is greater than b, then a, otherwise b". It's an expression, not a statement — meaning it produces a value you can store, return, or pass into something else. Used carefully, it makes code shorter without making it less readable. Used carelessly, it produces unreadable nests. Don't chain more than one or two.

Pitfalls to know about

Why this matters for AI

An if in your source code is, surprisingly, expensive at the chef level — particularly inside tight loops. The chef has a branch predictor that guesses, before the comparison is done, which way the branch will go, so it can keep its pipeline full. When the predictor is right (>95% of the time, typically), branches cost almost nothing. When it's wrong, the chef has to throw away its half-cooked work and start over — a "branch misprediction" — and that's a 15-cycle penalty.

This is why high-performance numerical code (matrix multiplication, AI inference kernels) tries to be branch-free. The same calculation is done unconditionally for every element, and the result is selected with a single masked operation rather than a conditional. The predictor never has to guess. The chef never stalls. You burn a few extra cycles of arithmetic, but you save an enormous amount of pipeline state.

"Predictable, dumb code" is the actual key to peak performance. If you ever find yourself writing a tight loop with a complex if in the middle, ask whether you can lift it out, vectorise the whole thing, or rewrite it without branching. The chef will thank you.

The simplest, oldest control structure — and yet the place modern CPUs spend the most ingenuity trying to predict.

Try it yourself

What's next

An if/else chain is fine for a few choices. When you have many — twenty different keys on a keyboard, sixty-four chess pieces, ten different command codes — there's a cleaner construct for that.

Week 15 is The Elevator — switch statements, jump tables, and how a compiler turns "match this against twenty options" into a single instruction.

Photo credit

Photo free under the Unsplash license. Forest path · Jens Lelie.