# What is the rule for when a semicolon is needed?

**URL:** <https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406>\
**Category:** Help\
**Tags:** language\
**Created:** [December 8, 2023, 8:21am UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406 "2023-12-08T08:21:30Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![zigo](https://ziggit.dev/user_avatar/ziggit.dev/zigo/32/2414_2.png) [@zigo](https://ziggit.dev/u/zigo)\
**Post date:** [December 8, 2023, 8:21am UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/1 "2023-12-08T08:21:30Z")

</div>

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.

```zig
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
}

```

---

<div class="post-metadata">

**Author:** ![neurocyte](https://ziggit.dev/user_avatar/ziggit.dev/neurocyte/32/3804_2.png) [@neurocyte](https://ziggit.dev/u/neurocyte)\
**Post date:** [December 8, 2023, 9:14am UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/2 "2023-12-08T09:14:58Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![zigo](https://ziggit.dev/user_avatar/ziggit.dev/zigo/32/2414_2.png) [@zigo](https://ziggit.dev/u/zigo)\
**Post date:** [December 8, 2023, 2:15pm UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/3 "2023-12-08T14:15:45Z")

</div>

You mean the inner ones are expressions, and the outer ones are statements. Right? (Reasonable)

Play it more:

This compiles:

```zig
pub fn main() void {
	var x: ?u8 = 5;
	
	if (x) |a|
		if (a > 0)
			std.debug.print("{}\n", .{a})
		else
			std.debug.print("{}\n", .{a})
	;

	if (x) |a|
		if (a > 0) {
			std.debug.print("{}\n", .{a});
		} else {
			std.debug.print("{}\n", .{a});
		}
	;
}

```

This also compiles:

```zig
pub fn main() void {
	var x: ?u8 = 5;
	
	_ = if (x) |a|
		if (a > 0)
			std.debug.print("{}\n", .{a})
		else
			std.debug.print("{}\n", .{a})
	
	;

	_ = if (x) |a|
		if (a > 0) {
			std.debug.print("{}\n", .{a});
		} else {
			std.debug.print("{}\n", .{a});
		}
	;
}

```

This compiles too:

```zig
pub fn main() void {
	var x: ?u8 = 5;
	
	if (x) |a|
		_ = if (a > 0)
			std.debug.print("{}\n", .{a})
		else
			std.debug.print("{}\n", .{a})
		;

	if (x) |a|
		_ = if (a > 0) {
			std.debug.print("{}\n", .{a});
		} else {
			std.debug.print("{}\n", .{a});
		}
	;
}

```

But this doesn’t:

```zig
pub fn main() void {
	var x: ?u8 = 5;
	
	_ = if (x) |a|
		_ = if (a > 0)
			std.debug.print("{}\n", .{a})
		else
			std.debug.print("{}\n", .{a})
	
	;

	_ = if (x) |a|
		_ = if (a > 0) {
			std.debug.print("{}\n", .{a});
		} else {
			std.debug.print("{}\n", .{a});
		}
	;
}

```

So a if-block can be used both as expression and statement. Whether or not it is sued as expression/statement is by context. Reasonable.

---

<div class="post-metadata">

**Author:** ![zigo](https://ziggit.dev/user_avatar/ziggit.dev/zigo/32/2414_2.png) [@zigo](https://ziggit.dev/u/zigo)\
**Post date:** [December 8, 2023, 2:29pm UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/4 "2023-12-08T14:29:07Z")

</div>

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.

```zig
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
}

```

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [December 8, 2023, 3:17pm UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/5 "2023-12-08T15:17:32Z")

</div>

just want to add a link to [related topic](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/1)

---

<div class="post-metadata">

**Author:** ![dude\_the\_builder](https://ziggit.dev/user_avatar/ziggit.dev/dude_the_builder/32/557_2.png) [@dude\_the\_builder](https://ziggit.dev/u/dude_the_builder)\
**Post date:** [December 8, 2023, 4:36pm UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/6 "2023-12-08T16:36:43Z")

</div>

> [@zigo](#):
>
> `if (x) |_| {} // here, {} is a statement`

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`.

---

<div class="post-metadata">

**Author:** ![zigo](https://ziggit.dev/user_avatar/ziggit.dev/zigo/32/2414_2.png) [@zigo](https://ziggit.dev/u/zigo)\
**Post date:** [December 8, 2023, 5:42pm UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/7 "2023-12-08T17:42:09Z")

</div>

> [@dude\_the\_builder](#):
>
> 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`.

If `{}` is an expression here, then why does the previous line `if (x) |_| y;` need a semicolon, but the `if (x) |_| {}` line doesn’t need?

---

<div class="post-metadata">

**Author:** ![dude\_the\_builder](https://ziggit.dev/user_avatar/ziggit.dev/dude_the_builder/32/557_2.png) [@dude\_the\_builder](https://ziggit.dev/u/dude_the_builder)\
**Post date:** [December 8, 2023, 8:15pm UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/8 "2023-12-08T20:15:03Z")

</div>

It seems that blocks do not allow semicolons after them.

```zig
{
    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.

---

<div class="post-metadata">

**Author:** ![zigo](https://ziggit.dev/user_avatar/ziggit.dev/zigo/32/2414_2.png) [@zigo](https://ziggit.dev/u/zigo)\
**Post date:** [December 9, 2023, 6:51am UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/9 "2023-12-09T06:51:39Z")

</div>

> [@dude\_the\_builder](#):
>
> So blocks are expressions.

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:

```zig
	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:

```zig
	var n:usize = 5;
	_ = switch (n) blk: { // error: expected '{', found 'an identifier'
		else => break: blk,
	};

```

---

<div class="post-metadata">

**Author:** ![zigo](https://ziggit.dev/user_avatar/ziggit.dev/zigo/32/2414_2.png) [@zigo](https://ziggit.dev/u/zigo)\
**Post date:** [December 9, 2023, 7:17am UTC](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/10 "2023-12-09T07:17:01Z")

</div>

> [@zigo](#):
>
> 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.
> 
> ```zig
> 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
> }
> 
> ```

After some research, here I try to make a clearer answer (than [@neurocyte](https://ziggit.dev/t/what-is-the-rule-for-when-a-semicolon-is-needed/2406/2%5D)).

After adding the required `;`, the quoted code can be re-written as

```zig
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

```zig
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

```zig
pub fn main() !void {
	const y: void = {};
	
	var x: ?u8 = 5;
	_ = x;
	
	y;

	y;
}

```

The final code compiles, but only if the type of `y` is `void`.

* * *

(I do still have some confusions on why sometimes a block can’t be followed by a semicolon.)
