<p>Some languages distinguish expressions from statements so that something like</p>
<pre class="lang-c prettyprint-override"><code>int x = 2;
foo((x += 2));
</code></pre>
<p>is invalid.
Other languages don't, so that a similar</p>
<pre class="lang-cl prettyprint-override"><code>(let ((x 2))
  (foo (incf x 2)))
</code></pre>
<p>is valid.</p>
<p>Under what criteria is it beneficial to distinguish the two, under what is it beneficial not to, and under what is it just a matter of preference?</p>
<hr />
<p><a href="https://languagedesign.stackexchange.com/q/974/171">This question</a> is similar, but it's asking about how to specify the distinction; whereas, I'm asking about under what conditions is the distinction meaningful or useful.</p>

<expressions><grammar><statements>
What are the advantages/disadvantages of distinguishing statements and expressions?
CC BY-SA 4.0
2023-06-02T22:51:33.010Z
@mousetail No, this is not a duplicate, it's asking about a design choice of whether to have both statements and expressions, not about what the meanings of those two words are.
kaya3
CC BY-SA 4.0
2023-06-04T02:03:06.600Z
It seems to me this question presupposes that such a distinction is something a language designer has control over, while it is a mental model representing the observation of properties of a given grammar.
Longinus
CC BY-SA 4.0
2023-06-09T19:38:43.720Z
@Longinus I agree that the distinction matters more as a mental model to a user of a language, but that doesn't mean that the designer of a language has no influence over how most developers will think of it
Aman Grewal
<h1>A statement is a node in a list, while an expression is a node in a tree.</h1>
<p>This is important, because a list is isomorphic to a tree formed by pairs whose right leaves recurse.<br />
That is, a list <code>x, y, z, w</code> is no different from a tree <code>x, (y, (z, w))</code>.</p>
<p>As it stands, even in &quot;expression-oriented&quot; languages such as Lisps or Haskell/MLs, statements can be introduced as easily as</p>
<pre class="lang-cl prettyprint-override"><code>(defun do
    [x ...xs] (ignore x (do xs...))
    [x] (return x))
</code></pre>
<p>or</p>
<pre class="lang-haskell prettyprint-override"><code>(;): a -&gt; b -&gt; b
x; xs = ignore x then xs
</code></pre>
<p>which can be used as</p>
<pre class="lang-cl prettyprint-override"><code>(do
    (println &quot;h&quot;)
    (println (time :UTC))
    (println 42))
</code></pre>
<p>and</p>
<pre class="lang-haskell prettyprint-override"><code>main =
    println &quot;h&quot;;
    println $ time UTC;
    println 42
</code></pre>
<p>respectively.<br />
Both are examples of statements in languages whose grammars have nothing called &quot;statement.&quot;</p>
<p>From the above, it then reasons that whether or not a language has first-class support for statements is a stylistic choice based on personal preferences.<br />
The main two reasons for a language designer to make such a choice are</p>
<ul>
<li>whether or not the language being worked on has a high number of built-in or heavily used operations which both
<ul>
<li>are to be used sequentially</li>
<li>and/or have no meaningful result,</li>
</ul>
</li>
<li>and way more importantly, how the language designer wants her language to look like.</li>
</ul>

CC BY-SA 4.0
2023-06-04T02:24:22.623Z
2023-06-04T02:31:15.820Z
2023-06-04T02:31:15.820Z
Longinus
CC BY-SA 4.0
2023-06-04T12:30:24.600Z
This is exactly how [Mathematica's `;` operator](https://reference.wolfram.com/language/ref/CompoundExpression.html) work.
alephalpha
CC BY-SA 4.0
2023-08-09T17:53:15.540Z
If `ignore x` means that x is discarded, and the language is lazily evaluated, then `println "h"; println $ time UTC; println 42` would do nothing, right?
Pablo H
CC BY-SA 4.0
2023-08-09T18:35:04.990Z
@PabloH Yes. This illustration expects strict evaluation with no complex IO typesystem. Under pure lazy evaluation, you'd use CPS, Monad's `>>=` operator, or something else of this order.
Longinus
<p>I second kaya3's answer, and I would add one category: declarations.</p>
<p>As an example of a statement-only thing, think of anything where it's a pure side effect. Storing a value atomically, declaring and setting a new variable, etc. C is not expression-oriented, but it's choice to make assignment an expression was a big mistake.</p>
<p>Similarly, declarations serve a different purpose: registering to the compiler something that does not translate to code.</p>
<p>So you have:</p>
<ul>
<li><strong>Declarations</strong>: Data for the compiler.</li>
<li><strong>Expressions</strong>: Code whose primary purpose is to produce a value.</li>
<li><strong>Statements</strong>: Code whose primary purpose is to produce a side effect.</li>
</ul>
<p>I am designing a language. Originally, it was going to be expression-only. I even found solutions to all of the problems in kaya3 mentioned.</p>
<p>Now, however, my language distinguishes between expressions, statements, and declarations.</p>

CC BY-SA 4.0
2023-06-03T02:14:59.723Z
2023-06-03T02:14:59.723Z
Gavin D. Howard
CC BY-SA 4.0
2024-12-19T21:19:42.977Z
It's easier for a compiler to efficiently generate code for `x=y=0;` than for `x=0; y=0;`.  While generating efficient code for the latter isn't exactly difficult, any extra memory compilers spent trying to optimize the latter form would be memory that was unavailable for other things that would likely be more useful.
supercat
<p>Particularly in the imperative paradigm, some kinds of statements don't make sense as expressions because there is no sensible value for them to have:</p>
<ul>
<li><code>if</code> statements, particularly when there is no <code>else</code> clause.</li>
<li><code>for</code> and <code>while</code> statements.</li>
<li><code>return</code>, <code>break</code>, <code>continue</code> and <code>throw</code> statements.</li>
<li>Function calls whose return type is <code>void</code>.</li>
</ul>
<p>That's not to say that these <em>can't</em> be made into expressions: an <code>if</code> without an <code>else</code> could have an <a href="https://en.wikipedia.org/wiki/Option_type" rel="noreferrer">optional</a> value, and it's definitely possible to have values for loop expressions (notably, in Rust a <code>loop</code> expression has a value given by a <code>break &lt;expr&gt;;</code> inside the loop).</p>
<p>Likewise, statements like <code>return</code> and <code>throw</code> do not &quot;complete normally&quot; so there is no need for them to have values even if they are expressions ─ but this does mean the language's type system needs to accommodate this, typically with a <a href="https://en.wikipedia.org/wiki/Bottom_type" rel="noreferrer">bottom type</a>. Similarly, <code>void</code> functions can return a special unit type, but then the language needs to make <code>void</code> a unit type.</p>
<p>So it would be possible for an imperative language to forego statements and have only expressions, but this would have impacts on what kinds of loops are possible in the language, and would impose requirements on the type system. Not every language necessarily wants option types and explicit bottom and unit types.</p>

CC BY-SA 4.0
2023-06-02T22:46:29.860Z
2023-06-02T23:09:21.337Z
2023-06-02T23:09:21.337Z
kaya3
CC BY-SA 4.0
2023-06-02T22:51:03.627Z
That's interesting, I certainly would not have thought about how this affects the type system. Do you have an example of a language that doesn't have an option type?
Aman Grewal
CC BY-SA 4.0
2023-06-02T22:54:07.913Z
@AmanGrewal All of the old-school imperative languages don't have option types in their standard libraries ─ C for example. Java didn't until 2014.
kaya3
CC BY-SA 4.0
2023-06-02T22:58:59.653Z
I can't speak for other languages, but is there a difference between "optional types" and a language (like C) that supports both null pointers and union types?
Aman Grewal
CC BY-SA 4.0
2023-06-02T22:59:39.903Z
Swift's optional is a tagged union, so `Optional<Int16>` is 3 bytes and `Optional<Int64>` is 9 bytes, for example.
Bbrk24
CC BY-SA 4.0
2023-06-02T23:00:49.487Z
Yes, [nullable types and optional types aren't the same](https://languagedesign.stackexchange.com/q/360/89), and also e.g. primitive `int` types generally can't be made nullable and have no niche for a sentinel `None` value in an undiscriminated union (like C's unions).
kaya3
# What are the advantages/disadvantages of distinguishing statements and expressions?
Posted by: username_0 on 2023-06-02
Some languages distinguish expressions from statements so that something like
int x = 2;
foo((x += 2));

is invalid.
Other languages don't, so that a similar
(let ((x 2))
  (foo (incf x 2)))

is valid.
Under what criteria is it beneficial to distinguish the two, under what is it beneficial not to, and under what is it just a matter of preference?

This question is similar, but it's asking about how to specify the distinction; whereas, I'm asking about under what conditions is the distinction meaningful or useful.
**Tags:** expressions grammar statements
> **Comments:**
> **username_1**: @mousetail No, this is not a duplicate, it's asking about a design choice of whether to have both statements and expressions, not about what the meanings of those two words are.  
> **username_2**: It seems to me this question presupposes that such a distinction is something a language designer has control over, while it is a mental model representing the observation of properties of a given grammar.  
> **username_0**: @Longinus I agree that the distinction matters more as a mental model to a user of a language, but that doesn't mean that the designer of a language has no influence over how most developers will think of it  
---
## 3 answers
### Answer by username_1 on 2023-06-02. Score: 10 | Accepted answer
Particularly in the imperative paradigm, some kinds of statements don't make sense as expressions because there is no sensible value for them to have:

* `if` statements, particularly when there is no `else` clause.
* `for` and `while` statements.
* `return`, `break`, `continue` and `throw` statements.
* Function calls whose return type is `void`.

That's not to say that these *can't* be made into expressions: an `if` without an `else` could have an [optional](https://en.wikipedia.org/wiki/Option_type) value, and it's definitely possible to have values for loop expressions (notably, in Rust a `loop` expression has a value given by a `break ;` inside the loop).

Likewise, statements like `return` and `throw` do not "complete normally" so there is no need for them to have values even if they are expressions ─ but this does mean the language's type system needs to accommodate this, typically with a [bottom type](https://en.wikipedia.org/wiki/Bottom_type). Similarly, `void` functions can return a special unit type, but then the language needs to make `void` a unit type.

So it would be possible for an imperative language to forego statements and have only expressions, but this would have impacts on what kinds of loops are possible in the language, and would impose requirements on the type system. Not every language necessarily wants option types and explicit bottom and unit types.
> **Comments:**
> **username_0** (2023-06-02): That's interesting, I certainly would not have thought about how this affects the type system. Do you have an example of a language that doesn't have an option type?  
> **username_1** (2023-06-02): @AmanGrewal All of the old-school imperative languages don't have option types in their standard libraries ─ C for example. Java didn't until 2014.  
> **username_0** (2023-06-02): I can't speak for other languages, but is there a difference between "optional types" and a language (like C) that supports both null pointers and union types?  
> **username_7** (2023-06-02): Swift's optional is a tagged union, so `Optional<Int16>` is 3 bytes and `Optional<Int64>` is 9 bytes, for example.  
> **username_1** (2023-06-02): Yes, [nullable types and optional types aren't the same](https://languagedesign.stackexchange.com/q/360/89), and also e.g. primitive `int` types generally can't be made nullable and have no niche for a sentinel `None` value in an undiscriminated union (like C's unions).  
---
### Answer by username_2 on 2023-06-04. Score: 5
A statement is a node in a list, while an expression is a node in a tree.
This is important, because a list is isomorphic to a tree formed by pairs whose right leaves recurse.
That is, a list x, y, z, w is no different from a tree x, (y, (z, w)).
As it stands, even in "expression-oriented" languages such as Lisps or Haskell/MLs, statements can be introduced as easily as
(defun do
    [x ...xs] (ignore x (do xs...))
    [x] (return x))

or
(;): a -> b -> b
x; xs = ignore x then xs

which can be used as
(do
    (println "h")
    (println (time :UTC))
    (println 42))

and
main =
    println "h";
    println $ time UTC;
    println 42

respectively.
Both are examples of statements in languages whose grammars have nothing called "statement."
From the above, it then reasons that whether or not a language has first-class support for statements is a stylistic choice based on personal preferences.
The main two reasons for a language designer to make such a choice are

whether or not the language being worked on has a high number of built-in or heavily used operations which both

are to be used sequentially
and/or have no meaningful result,


and way more importantly, how the language designer wants her language to look like.
> **Comments:**
> **username_3** (2023-06-04): This is exactly how [Mathematica's `;` operator](https://reference.wolfram.com/language/ref/CompoundExpression.html) work.  
> **username_4** (2023-08-09): If `ignore x` means that x is discarded, and the language is lazily evaluated, then `println "h"; println $ time UTC; println 42` would do nothing, right?  
> **username_2** (2023-08-09): @PabloH Yes. This illustration expects strict evaluation with no complex IO typesystem. Under pure lazy evaluation, you'd use CPS, Monad's `>>=` operator, or something else of this order.  
---
### Answer by username_5 on 2023-06-03. Score: 3
I second kaya3's answer, and I would add one category: declarations.

As an example of a statement-only thing, think of anything where it's a pure side effect. Storing a value atomically, declaring and setting a new variable, etc. C is not expression-oriented, but it's choice to make assignment an expression was a big mistake.

Similarly, declarations serve a different purpose: registering to the compiler something that does not translate to code.

So you have:

* **Declarations**: Data for the compiler.
* **Expressions**: Code whose primary purpose is to produce a value.
* **Statements**: Code whose primary purpose is to produce a side effect.

I am designing a language. Originally, it was going to be expression-only. I even found solutions to all of the problems in kaya3 mentioned.

Now, however, my language distinguishes between expressions, statements, and declarations.
> **Comments:**
> **username_6** (2024-12-19): It's easier for a compiler to efficiently generate code for `x=y=0;` than for `x=0; y=0;`.  While generating efficient code for the latter isn't exactly difficult, any extra memory compilers spent trying to optimize the latter form would be memory that was unavailable for other things that would likely be more useful.  
---
