# A (probably stupid) terminological question

**URL:** <https://ziggit.dev/t/a-probably-stupid-terminological-question/2185>\
**Category:** Brainstorming\
**Tags:** language\
**Created:** [November 11, 2023, 4:43pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185 "2023-11-11T16:43:00Z")\
**Posts on this page:** 20\
**Page:** 1

<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:** [November 11, 2023, 4:43pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/1 "2023-11-11T16:43:01Z")

</div>

Hi.

I have a question about {expression,statement,operator} terms.

I took a look at [this explanation](https://www.freecodecamp.org/news/statement-vs-expression-whats-the-difference-in-programming) and after

> Though the function is now an expression the way it is called above, the whole of the code is still a statement

my mind was broken 😫

So, what is exact meaning of the terms above (“statement”, “expression”, “operator”) in Zig?

For example, in, say

```zig
const below_zero: bool = if (a < 0) true else false;

```

where are statements, where are operators, where are expressions?

Thanks.

---

<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:** [November 11, 2023, 6:33pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/2 "2023-11-11T18:33:11Z")

</div>

Haven’t read the linked artible, but from what I’ve previously gathered:

- Operators: `=` and `<`
- Expressions: `a`, `0`, `true`, `false`, and `if (a < 0) true else false`
- Statement: `const below_zero: bool = if (a < 0) true else false`

Or in other words, expressions produce a value, statements don’t. Operators perform actions on operands. That’s pretry much it.

---

<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:** [November 11, 2023, 6:55pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/3 "2023-11-11T18:55:41Z")

</div>

> [@dude\_the\_builder](#):
>
> if (a \< 0) true else false

- is ‘`if (a < 0) true else false`’ statement or expression?
- is ‘`if (a < 0) true else false;`’ statement or expression?

Or, in other words… 🫥-

- does ‘`if (a < 0) true else false`’ produce a value?
- does ‘`if (a < 0) true else false;`’ produce a value?

---

<div class="post-metadata">

**Author:** ![desttinghim](https://ziggit.dev/user_avatar/ziggit.dev/desttinghim/32/70_2.png) [@desttinghim](https://ziggit.dev/u/desttinghim)\
**Post date:** [November 11, 2023, 7:44pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/4 "2023-11-11T19:44:38Z")

</div>

`if (a < 0) true else false` is an expression, it returns a boolean. `if (a < 0) true else false;` is an invalid statement in zig since it is an expression that returns a value and values cannot be implicitly discarded. To make it valid statement, it can be changed to explicitly discard the value: `_ = if (a < 0) true else false;`. A statement requires some sort of operation to occur, often an assignment.

---

<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:** [November 11, 2023, 8:32pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/5 "2023-11-11T20:32:04Z")

</div>

In addition to what @desttinghim writes, the flexibility that Zig’s `if` allows can make this topic even more confusing. In Zig, if you want to use `if` as an expression, you cannot use the curly braces around the branches and the else branch is mandatory:

```zig
const below_zero = if (a < 0) true else false; // OK

const below_zero = if (a < 0)
    true
else
    false; // OK

const below_zero = if (a < 0) { true } else {false }; // error
const below_zero = if (a < 0) true; // error
const below_zero = if (a < 0) { true }; // error

const below_zero = if (a < 0) true else 13; // error, must produce same type

```

An `if` with the curly braces around the branches is not an expression, it’s a statement. Like function bodies, there’s no semicolon after the closing brace. The else branch is optional.

```zig
if (a < 0) {
    print("Below zero!\n", .{});
}

if (a < 0) {
    print("Below zero!\n", .{});
} else {
    print("Above zero!\n", .{});
}

```

What can be a little confusing is when you mix in labeled blocks, which you can use in an `if` expression, making it look like an `if` statement with curly braces:

```zig
const below_zero = if (a < 0) blk: {
    break :blk true;
} else blk: {
    break blk: false;
};

```

But even so, the labels are pretty easy to spot, enough to differentiate this from an `if` statement.

---

<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:** [November 12, 2023, 11:21am UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/6 "2023-11-12T11:21:29Z")

</div>

> [@dude\_the\_builder](#):
>
> if you want to use `if` as an expression

What is `if` by itself? An (unary) operator? Or what?

---

<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:** [November 12, 2023, 11:33am UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/7 "2023-11-12T11:33:02Z")

</div>

> [@desttinghim](#):
>
> `if (a < 0) true else false` is an expression, it returns a boolean

Yes, it has a value.

```zig
const std = @import("std");

pub fn main() void {
    const t: i32 = -7;
    if (if (t < 0) true else false)
        std.debug.print("<0\n", .{});
}

```

but `if (t < 0) true else false;` does not have a value

```zig
const std = @import("std");

pub fn main() void {
    const t: i32 = -7;
    if (if (t < 0) true else false;)
        std.debug.print("<0\n", .{});
}

```

```zig
$ /opt/zig-0.11/zig run if.zig 
if.zig:6:35: error: expected ')', found ';'
    if (if (t < 0) true else false;)

```

It does not have a value, but we can assign this nonexistent value to a var. 🙂  
Ok, we are assigning the value of `if (t < 0) true else false`.  
Does that mean that `';'` is a terminator for `'='`?!?!?

---

<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:** [November 12, 2023, 12:21pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/8 "2023-11-12T12:21:47Z")

</div>

`if` by itself is just a keyword. It only becomes an expression or a statement depending on how you combine it with other expressions or statements.

---

<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:** [November 12, 2023, 12:35pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/9 "2023-11-12T12:35:16Z")

</div>

> [@dude\_the\_builder](#):
>
> `if` by itself is just a keyword

`pub` by itself is also just a keyword.  
`and` by itself is also just a keyword, but it’s also a (binary) operator.  
`pub` is not an operator.

---

<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:** [November 12, 2023, 12:35pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/10 "2023-11-12T12:35:59Z")

</div>

> [@dee0xeed](#):
>
> Does that mean that `';'` is a terminator for `'='`?!?!?

The `;` terminates a statement, and in Zig, an assignment using the `=` operator is a statement. Note that in other languages, `=` is an expression like in:

```c
a = b = c;

```

But this has led to bugs when you mistakenly use `=` when you meant `==`. So most _new_ langueges don’t treat `=` assignment as an expression any more. The same has happened with the `++` and `--` operators. In ancient (lol) languages, these are expressions:

```zig
a = c++;
a = ++c;

```

But once again, this has led to much confusion and bugs when the programmer is not clear on what the actual value being returned is. In Go, they have postfix `++` and `--` only and they are not expressions to avoid this confusion. In zig, they’re simply not included at all and you have to use `+=` or `-=` which are not expressions either.

So back to `if`, I guess it’s hard to put it in a single category in Zig, given it can serve as an expression and a statement. The same is true for `while`, `for`, and `switch` which all have expression and statement forms.

---

<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:** [November 12, 2023, 12:46pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/11 "2023-11-12T12:46:21Z")

</div>

> [@dude\_the\_builder](#):
>
> The `;` terminates a statement

So, statement is _something_ terminated by `';'`, right?

> [@dude\_the\_builder](#):
>
> when you mistakenly use `=` when you meant `==`

In case of comparing with constants there is simple way to avoid such mistakes, just make the constant lhs:

```zig
if (NULL == ptr)

```

> [@dude\_the\_builder](#):
>
> So back to `if`, I guess it’s hard to put it in a single category in Zig, given it can serve as an expression and a statement

`if` by itself is neither expression nor statement.

---

<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:** [November 12, 2023, 12:53pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/12 "2023-11-12T12:53:43Z")

</div>

> [@dude\_the\_builder](#):
>
> So most _new_ langueges don’t treat `=` assignment as an expression any more

I know. 🙂  
`=` by itself is not an expression, it’s a an operator.  
with some lhs and `;` somewhere below it becomes a statement, right?

---

<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:** [November 12, 2023, 2:42pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/13 "2023-11-12T14:42:28Z")

</div>

> [@dee0xeed](#):
>
> with some lhs and `;` somewhere below it becomes a statement, right?

Right. So to put it in the most fundamental way, in Zig all statements must end with `;` and expresiions by themselves are not statements, so that’s why your example code `if (a < 0) true else false;` is not valid Zig code (as @desttinghim pointed out above.)

There are languages that allow _expression statements_ like `a + b;`, but not Zig. In Zig the value returned from an expression must be used and cannot be ignored. Even discarding it with `_ = a + b;` counts as using the value.

---

<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:** [November 12, 2023, 3:18pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/14 "2023-11-12T15:18:49Z")

</div>

> [@dude\_the\_builder](#):
>
> There are languages that allow _expression statements_

oh, yeah! - [statement expressions](https://ziggit.dev/t/outreach-looking-for-a-simple-example-of-using-comptime-instead-of-macros/2106/16)

“expression statements”, “statement expressions”  
Curiouser and curiouser! 🙂

---

<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:** [November 12, 2023, 4:50pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/15 "2023-11-12T16:50:53Z")

</div>

> [@desttinghim](#):
>
> A statement requires some sort of operation to occur, often an assignment

Are there any examples of “statements”, that do not require an assignment?

---

<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:** [November 12, 2023, 5:46pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/16 "2023-11-12T17:46:37Z")

</div>

I think they are very rare indeed. Not 100% sure, but I think these are statements in Zig:

- `defer foo.deinit();`
- `errdefer foo.deinit();`
- `for (0..3) |i| { print("{}", .{i}) }`
- `while (i < 3) |i| : (i += 1) { print("{}", .{i}); }`
- `switch (a) { 0 => print("0", .{}), else => |x| print("{}", .{x}) }`
- `if (a < 0) { print("<", .{}); } else { print(">=", .{}); }`

---

<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:** [November 12, 2023, 6:02pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/17 "2023-11-12T18:02:06Z")

</div>

> [@dude\_the\_builder](#):
>
> - `defer foo.deinit();`
> - `errdefer foo.deinit();`

**explicit** `goto` was better imho

---

<div class="post-metadata">

**Author:** ![IntegratedQuantum](https://ziggit.dev/user_avatar/ziggit.dev/integratedquantum/32/782_2.png) [@IntegratedQuantum](https://ziggit.dev/u/IntegratedQuantum)\
**Post date:** [November 12, 2023, 6:14pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/18 "2023-11-12T18:14:08Z")

</div>

> [@dude\_the\_builder](#):
>
> I think they are very rare indeed. Not 100% sure

Calling a void function is a statement, too, right? And that’s pretty common.

- `foo.update();`
- `try foo.update();`

---

<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:** [November 12, 2023, 7:44pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/19 "2023-11-12T19:44:44Z")

</div>

> [@IntegratedQuantum](#):
>
> Calling a void function is a statement, too, right?

This can be one of two options:

1. A function always returns a value, and in the case of `void`, that’s the only value the language allows you to ignore.
2. A function with return type `void` actually doesn’t return any value.

Given that in Zig there is an actual `noreturn` return type, I was inclined to believe option 1 was the case. Also, when `return` is followed by something, it has to be the value to return, so it does seem that a call to a void function returns a void value given this:

```zig
fn voidFunc1() void {}

fn voidFunc2() void {
    return voidFunc1();
}

```

---

<div class="post-metadata">

**Author:** ![chung-leong](https://ziggit.dev/user_avatar/ziggit.dev/chung-leong/32/999_2.png) [@chung-leong](https://ziggit.dev/u/chung-leong)\
**Post date:** [November 12, 2023, 8:24pm UTC](https://ziggit.dev/t/a-probably-stupid-terminological-question/2185/20 "2023-11-12T20:24:40Z")

</div>

A term missing from this discussion is “side-effect”. In general, statements have side-effects, meaning they cause changes to the environment, whereas expressions do not. The expression `a + b` doesn’t change anything. The statement `c = a + b;` does. Whatever stored in `c` previously is lost forever, replaced by the outcome of the addition expression.

Assignment to variables is the most common side-effect. There’re also operations like printing to the screen or outputting to a network connection.

Expressions can have side-effects, but that’s something we try to avoid since they make a program harder to understand. Obviously, programming with the use of variables is not very practical. We do try our best to isolate the side-effects, either within a function scope or within an object.
