if
A choice between two branches on a bit condition. As an expression it has a value and the else is
mandatory; as a statement it has no value and each branch is a list of statements.
const raw_bearing_deg: int32 = 400;
const bearing_deg: int32 = if raw_bearing_deg > 360 then raw_bearing_deg - 360 else raw_bearing_deg;Branches
The condition has type bit, only the taken branch evaluates, and the whole if has the type the two
branches share.
- The
elseis required. Anifwithout one is a parse error. - Both branches must have a common type, which is the type of the expression.
- Two structs in the same hierarchy have their nearest common ancestor as that type.
- Two different numeric widths have no common type.
int32andint64branches are rejected. - There is no
else if. The else branch is anotherif, which is why the chain reads as one.
extensible struct Contact {
contact_id: uint32;
}
struct Radar extends Contact {
scan_period_ms: uint32;
}
struct Sonar extends Contact {
depth_m: uint32;
}
const from_air: bit = true;
const primary: Contact =
if from_air then Radar { contact_id = 1; scan_period_ms = 2000; }
else Sonar { contact_id = 2; depth_m = 40; };
const range_m: int32 = 8000;
const band: int32 = if range_m > 10000 then 3 else if range_m > 5000 then 2 else 1;Spellings
then is optional, parentheses around the condition are just a parenthesized expression, and a braced
branch is just a block. None of them is a separate form, so they mix
freely and all of these are the same if.
const armed: bit = true;
if armed then "on" else "off" // => "on"
if armed "on" else "off" // => "on"
if (armed) then "on" else "off" // => "on"
if armed { "on"; } else { "off"; } // => "on"
if armed then { "on"; } else "off" // => "on"A { after the condition always opens the then-branch, so a condition that ends in a struct literal
has to be parenthesized.
struct Threshold {
limit_deg: uint16;
}
const over: bit = if (Threshold { limit_deg = 90; }).limit_deg > 0 { true; } else { false; };Statement form
Written with a bare then-branch, if is a statement: it produces no value and each branch is a list of
statements. It belongs in a block before the tail expression, or in a contract body.
- The then-branch decides which form this is. Bare makes it a statement; braced makes it an expression, and both branches then need a tail value.
- Given a bare then-branch, the
elsemay be one bare statement or a braced list of them. Theelseis still mandatory. - Each branch is its own scope. A
letin a branch is invisible to the other branch and to everything after theif, where it would otherwise exist on only one execution path. - A contract body has no tail expression, so both branches may be braced statement lists there.
function bounded(raw_range_m: int32) -> int32 = {
if raw_range_m > 0 then assert raw_range_m < 100000;
else assert raw_range_m > -100000;
raw_range_m;
};
contract InSector(bearing_deg: int32) {
if bearing_deg > 180 { assert bearing_deg <= 360; }
else { assert bearing_deg >= 0; }
assert true;
}Errors
A condition that is not bit
const armed: bit = if (1: int32) then true else false; // error: type-mismatchBranches with no common type
const label: string = if true then "inbound" else 42; // error: incompatible-branch-typesBranches of two different numeric widths
const range_m: int64 = if true then (1: int32) else (2: int64); // error: incompatible-branch-typesRelated
- block, let, assert — the statements a branch is made of, and the block a braced branch is.
- match — the choice over more than two cases, which also destructures.
- operators — the comparisons a condition is usually built from.