In the two if-blocks shown below, the second needs a semicolon to compile.
I failed to find the rule for when a semicolon is needed.
pub fn main() void {
var x: ?u8 = 5;
if (x) |a|
if (a > 0)
std.debug.print("{}\n", .{a});
if (x) |a|
if (a > 0) {
std.debug.print("{}\n", .{a});
} // need a ; here
}
One is an if expression, the other is an if statement.
Basically, if the “if” is followed by a block it does not need a semicolon, otherwise it does. The commented semicolon in your example terminates the outer if, which has no block. The inner if has a block and does not need the semicolon.
I don’t know whether or not my understanding is correct. It looks to me that the similar situation is for {}. Sometimes, it is an expression, sometimes, it is a statement.
pub fn main() void {
var x: ?u8 = 5;
var y: void = {}; // here, {} is an expression
if (x) |_| y;
if (x) |_| {} // here, {} is a statement
_ = if (x) |_| {}; // here, {} is an expression
if (x) |a| if (a > 0) {}; // here, {} is an expression
}
I think that in this case, the entire if is the statement, not needing ; because it has a block, albeit an empty one {} which is an expression that evaluates to void.
It seems that blocks do not allow semicolons after them.
{
var x: u8 = 3;
x += 1;
} // try to add a semicolon here, you'll get an error
{} // here too
blk: {
break :blk;
} // here too
So blocks are expressions, but have special syntactical treatment when it comes to semicolons it seems. Also, the empty block {} which evaluates to void is the only expression you can ignore without error.
Just checked Zig documentation. It does mentions this speaking. It also mentions “statement” many times, but doesn’t give the word a definition. The fact that it mentions “statements” and “expressions” together many times indicates the two words have the same meaning as other languages.
My current understanding is the speaking “blocks are expressions” is not accurate. Instead, “blocks can be used as expressions” is more accurate. Much code shows that blocks are not always expressions. The following is another example:
var y: void = {}; // as expression
y; // legal only if y is void
{} // as statement. Here, ; is not allowed.
The following is another case in which {...} is absolutely not an expression:
After some research, here I try to make a clearer answer (than @neurocyte).
After adding the required ;, the quoted code can be re-written as
pub fn main() !void {
var x: ?u8 = 5;
if (x) |a|
if (a > 0)
std.debug.print("{}\n", .{a})
;
if (x) |a|
if (a > 0) {
std.debug.print("{}\n", .{a});
}
;
}
The two inner if-blocks block both act as expressions (of type void). In fact, by ignoring the output, the re-written code is equivalent to
pub fn main() !void {
const y: void = {};
var x: ?u8 = 5;
if (x) |_|
y
;
if (x) |_|
y
;
}
In fact, without the final semicolons, the two outer if-blocks are also both expressions. The above code can further re-written as