Control flow · Lesson 3.1

If

Source
Run a block only when a condition holds, and pick between two blocks with else.
You'll need: Comparison, Logical

Until now, every program has run every line, top to bottom, every time. Real programs react: they print a warning only when something is wrong, charge a fee only when it applies, take a different path when the input is different. if is the simplest way to make that choice — run a block of code only when a condition holds.

Run a block, or skip it

An if is the keyword, a condition, and a block in braces:

let temperature: int32 = 18;

if temperature > 15 {
    PrintLine("warm enough for a walk");
}
if temperature > 25 {
    PrintLine("hot enough for a swim");
}

18 is above 15, so the first block runs. It is not above 25, so the second block is skipped. Either way, the program carries on with whatever comes after the closing brace.

Parentheses optional, braces required

Parentheses around the condition are allowed but never needed:

if (temperature < 20) {
    PrintLine("bring a jacket");
}

The braces are the opposite: always needed, even around a single statement. if ready PrintLine("go"); is an error. Because the braces are always there, there is never any doubt about which lines belong to the if.

else: one of two

Add else, and exactly one of two blocks runs — the first when the condition holds, the second when it does not:

let raining = true;
if raining {
    PrintLine("take an umbrella");
} else {
    PrintLine("leave the umbrella at home");
}
flowchart LR
    c{"raining?"} -- "true" --> a["take an umbrella"]
    c -- "false" --> b["leave the umbrella at home"]
    a --> next["the next statement"]
    b --> next

The two paths always meet again after the if. There is no way for both blocks to run, and no way for neither to.

The condition is a bool

A condition must be a bool: a comparison, a logical expression from Logical, or a bool variable. Anything that produces a bool will do:

let windy = true;
if raining && !windy {
    PrintLine("the umbrella will do");
} else {
    PrintLine("wear a hood instead");
}

Rux has no "truthy" numbers, so a number is not a shortcut for "not zero". if count { } is refused; write the comparison you mean, if count != 0 { }.

Blocks and the variables around them

A block may read and change variables declared before it:

var budget: int32 = 12;
let price: int32 = 9;
if price <= budget {
    budget -= price;
    PrintLine("bought it, {} left", budget);
} else {
    PrintLine("cannot afford it");
}

budget lives outside the if, so the change survives after the closing brace. A variable declared inside a block is different: it belongs to the block, and it is gone once the block ends. To use a value after the if, declare its variable before it.

if decides while the program runs. Rux also has when, which decides while the program is being compiled — that one comes much later, in When.

The program

The whole lesson is one package in the Examples repository. Its comments explain every step.

Src/Main.rux
// `if` runs a block only when its condition is true. Add `else`, and exactly one of two blocks
// runs: the first when the condition holds, the second when it does not.
//
// The condition must be a `bool`: a comparison, a logical expression, or a `bool` binding. Rux has
// no "truthy" numbers, so a number is not a shortcut for "not zero":
//
//     if count { }
//         error: condition for 'if' must have type 'bool', but found 'int'
//
// Write the comparison you mean instead, `if count != 0 { }`.
//
// `if` decides while the program runs. Rux also has `when`, which decides while the program is
// being compiled; that one comes much later, in the When lesson.
import Io::PrintLine;

func Main() -> int {
    let temperature: int32 = 18;

    // Without `else`, the block either runs or is skipped, and the program carries on after it.
    if temperature > 15 {
        PrintLine("warm enough for a walk");
    }
    if temperature > 25 {
        PrintLine("hot enough for a swim");
    }

    // Parentheses around the condition are allowed but never needed. The braces are always
    // needed, even around a single statement: `if ready PrintLine("go");` is an error.
    if (temperature < 20) {
        PrintLine("bring a jacket");
    }

    // With `else`, one of the two blocks always runs.
    let raining = true;
    if raining {
        PrintLine("take an umbrella");
    } else {
        PrintLine("leave the umbrella at home");
    }

    // Any `bool` expression is a condition, including ones built with `&&`, `||` and `!`.
    let windy = true;
    if raining && !windy {
        PrintLine("the umbrella will do");
    } else {
        PrintLine("wear a hood instead");
    }

    // A block may change variables declared before it. A binding declared inside the block,
    // though, belongs to the block and is gone after its closing brace.
    var budget: int32 = 12;
    let price: int32 = 9;
    if price <= budget {
        budget -= price;
        PrintLine("bought it, {} left", budget);
    } else {
        PrintLine("cannot afford it");
    }
    return 0;
}

Run it

cd Examples/ControlFlow/If
rux run
warm enough for a walk
bring a jacket
take an umbrella
wear a hood instead
bought it, 3 left

Common mistakes

Using a number as a condition.
if count { } fails with error: condition for 'if' must have type 'bool', but found 'int'. Write the test you mean: if count != 0 { }.
Leaving out the braces.
if ready PrintLine("go"); fails with error: expected '{' to start the 'if' body before 'PrintLine'. Every if and else body is a block in braces.
Using a block's variable after the block.
A let change = 10 - price; declared inside the if cannot be printed after it: error: name 'change' is not defined in this scope. Declare the variable before the if — a var, if each branch assigns it.
Writing = for ==.
if age = 18 { } is an assignment, not a question, and it is refused with error: condition for 'if' must have type 'bool', …. Comparison takes two equals signs.

Try it yourself

  1. Change temperature to 30, then to 10, and predict which lines print each time.
  2. Add an if that prints "freezing" when the temperature is below 0.
  3. Make the shop example buy two items in a row, each with its own if, and print what is left.
  4. Write if raining { … } else { … } using !raining instead, with the blocks swapped. Does the output change?

Learn more

  • if / else in the Rux Reference
  • Else if — choosing among more than two cases
  • Ternary — choosing between two values inside an expression