If
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 --> nextThe 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.
// `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
if count { } fails with error: condition for 'if' must have type 'bool', but found 'int'. Write the test you mean: if count != 0 { }.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.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.= 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
- Change
temperatureto30, then to10, and predict which lines print each time. - Add an
ifthat prints"freezing"when the temperature is below 0. - Make the shop example buy two items in a row, each with its own
if, and print what is left. - Write
if raining { … } else { … }using!raininginstead, with the blocks swapped. Does the output change?