<p>Suppose I would add an optional else branch to the for statement, with whatever semantics. Or even harder, that I would allow the programmer to define custom ternary operators, with the third operand being optional.</p>
<p>How to design it so that it would not surprise programmers get used to similar constructs, say if ... else?</p>
<p>For example, if the following code is translated to the language, <code>else</code> should always pair with <code>if</code>. And there should be a different way to make it pair with <code>for</code>.</p>
<pre><code>if(condition)
    for(;;)
        body;
else
    fallback;
</code></pre>
<p>This is easy in Python, Lisp or endif-style grammars. But I want to know if there is a reasonable way for every (non-esoteric) type of grammar. Specifically, I want it to work in a language with the basic grammar as close to C as possible.</p>

<grammar>
What are the ways to define optionally binary / ternary operators with shared keywords (e.g. for ... else) without unintended ambiguities?
CC BY-SA 4.0
2024-12-08T09:49:31.917Z
Isn't this basically the same as the problem of multiple `else if` statements? And the solution is probably the same: by default, `else` pairs with the most recent `if` or `for`, and you use braces to override this default.
Barmar
CC BY-SA 4.0
2024-12-09T04:41:36.100Z
What about this is specific to having two separate statement kinds? It looks like you would have the same problem when just nesting two `if` statements.
MisterMiyagi
CC BY-SA 4.0
2024-12-09T21:02:40.230Z
Yes, `if(a) if(b) c; else d;` is already ambiguous if you don't require braces around the branches.
kaya3
CC BY-SA 4.0
2024-12-09T22:34:14.950Z
The point is the normal way of resolving ambiguity would confuse programmers unaware of the existence of for ... else.
user23013
CC BY-SA 4.0
2024-12-10T13:46:36.710Z
This is known as the [Dangling else](https://en.wikipedia.org/wiki/Dangling_else) problem
Kninnug
<p>This is known as <a href="https://en.wikipedia.org/wiki/Dangling_else" rel="nofollow noreferrer">the dangling else problem</a> and it can be formulated and resolved at different levels.</p>
<p>Level 1 is the syntactic level. We can avoid the problem syntactically; this is usually done by adding brackets of some kind. For instance, <a href="https://en.wikipedia.org/wiki/ALGOL_68" rel="nofollow noreferrer">ALGOL 68</a> has</p>
<pre><code>IF ...
THEN
  ...
FI
</code></pre>
<p>An <code>ELSE</code> part is optional.</p>
<p>Because the <code>THEN</code> and <code>FI</code> are required, the <code>...</code>s may contain arbitrary sequences of statements, and arbitrary nested occurrences of this construct, without producing ambiguity.</p>
<p>ALGOL 68's ternary &quot;operator&quot; is simply <code>IF ... THEN ... ELSE ... FI</code>, i.e. the same construct (ALGOL 68 allows statements wherever expressions are allowed, and vice versa).</p>
<p>More languages use this approach, e.g. the Bourne shell.</p>
<p>An alternative is to require brackets around all sequences of statements/expressions. E.g. always require the brackets in <code>if ( ... ) { ... }</code>. Many languages do this.</p>
<p>You're asking: what if we don't. Many languages don't; for instance, C and Pascal.</p>
<p>This is level 2: our syntax doesn't protect us, so we need a defense at the semantic level.</p>
<p>The standard defense: precedence rules. We really don't care what the grammar for <code>a * b + c * d</code> looks like, but we disambiguate it using the precedence rule that <code>*</code> binds more strongly than <code>+</code>.</p>
<p>Similarly, we have precedence rules to disambiguate <code>a ? b ? c : d</code>, and <code>if (a) b; c</code>, and <code>if (a) if (b) c else d</code>, and whatever else. Users will need to look them up and apply them correctly every time, and if they're smart they will put in extra brackets anyway, but it is up to them, and as a consequence, lots of errors will still be made, because the language invites them.</p>
<p>Some programmers prefer this approach anyway. <a href="https://xkcd.com/297/" rel="nofollow noreferrer">Not everyone is happy</a> with <a href="https://en.wikipedia.org/wiki/Lisp_(programming_language)" rel="nofollow noreferrer">Lisp</a> syntax.</p>
<p>So now, I hear you ask, let's take for granted that our language is like this, and that programmers are like this, is there still something we can do? A level 3 defense?</p>
<p>Yes, there is: we can make our compiler (or a separate syntax checker) throw warnings whenever it meets a construct that looks like it may have a precedence error. We can even have several levels of verbosity and at the highest level have it ask for <em>every</em> construct that relies on a precedence rule whether the programmer meant to write that or the alternative. We can even have it insert brackets upon request.</p>
<p>This may be the best of both worlds: it allows the language to be permissive, while users and teams can still enforce non-permissive coding standards, even ones that completely eliminate all ambiguity.</p>

CC BY-SA 4.0
2024-12-26T19:07:18.353Z
2024-12-26T19:17:39.527Z
2024-12-26T19:17:39.527Z
reinierpost
<p>Note how even for an <code>if</code> without an <code>else</code> there is some ambiguity:</p>
<pre><code>if expression1 expression2;
</code></pre>
<p>Because where does <code>expression1</code> end and <code>expression2</code> begin? In C this ambiguity is resolved by requiring <code>expression1</code> to be wrapped in parentheses. Rust does this the opposite way: <code>expression2</code> must be wrapped in curly braces. The latter actually solves the ambiguity of the <code>else</code> clause. Consider this bad example in C:</p>
<pre><code>if (foo)
   if (bar)
      baz();
else
   quux();
</code></pre>
<p>If you wrote something similar in Rust:</p>
<pre><code>if foo {
    if bar {
        baz();
} else {
    quux();
}
</code></pre>
<p>It would be a syntax error, as there is a closing curly brace missing, and where you will put it will determine if the <code>else</code>-clause belongs to the inner or the outer <code>if</code>.</p>

CC BY-SA 4.0
2024-12-08T12:56:02.023Z
2024-12-08T12:56:02.023Z
G. Sliepen
<p>A simple solution is to require an <code>end</code> keyword. Then you can parse your expression easily, depending on the first keyword (if/for/etc) and optional arguments are covered because the <code>end</code> makes it distinct.</p>
<p>Then you can distinct between</p>
<pre><code>if(condition)
    for(;;)
        body
    end
else
    fallback
end
</code></pre>
<p>and</p>
<pre><code>if(condition)
    for(;;)
        body
    else
      fallback
    end
end
</code></pre>
<p>just by the different placement of the <code>end</code> keywords (thanks to @ChrisDodd for pointing this out).</p>
<p>Another example:</p>
<pre><code>if x + if y then 1 else 2 end = 5 then for y in array do x+=y end end
</code></pre>

CC BY-SA 4.0
2024-12-08T20:22:37.470Z
2024-12-10T08:37:38.663Z
2024-12-10T08:37:38.663Z
return true
CC BY-SA 4.0
2024-12-10T05:26:56.617Z
Actually, if the `end` is *always* required (in a `for` statement as well as an `if`), it does solve the problem -- the placement of the `end` for the `for` determines whether the `else` binds to the `for` (`else` before `end`) or the `if` (`else` after then `end` for the `for`).
Chris Dodd
CC BY-SA 4.0
2024-12-10T08:35:33.497Z
@ChrisDodd oh, you are right! I missed that, I'll edit my answer accordingly.
return true
# What are the ways to define optionally binary / ternary operators with shared keywords (e.g. for ... else) without unintended ambiguities?
Posted by: username_0 on 2024-12-08
Suppose I would add an optional else branch to the for statement, with whatever semantics. Or even harder, that I would allow the programmer to define custom ternary operators, with the third operand being optional.
How to design it so that it would not surprise programmers get used to similar constructs, say if ... else?
For example, if the following code is translated to the language, else should always pair with if. And there should be a different way to make it pair with for.
if(condition)
    for(;;)
        body;
else
    fallback;

This is easy in Python, Lisp or endif-style grammars. But I want to know if there is a reasonable way for every (non-esoteric) type of grammar. Specifically, I want it to work in a language with the basic grammar as close to C as possible.
**Tags:** grammar
> **Comments:**
> **username_1**: Isn't this basically the same as the problem of multiple `else if` statements? And the solution is probably the same: by default, `else` pairs with the most recent `if` or `for`, and you use braces to override this default.  
> **username_2**: What about this is specific to having two separate statement kinds? It looks like you would have the same problem when just nesting two `if` statements.  
> **username_3**: Yes, `if(a) if(b) c; else d;` is already ambiguous if you don't require braces around the branches.  
> **username_0**: The point is the normal way of resolving ambiguity would confuse programmers unaware of the existence of for ... else.  
> **username_4**: This is known as the [Dangling else](https://en.wikipedia.org/wiki/Dangling_else) problem  
---
## 3 answers
### Answer by username_6 on 2024-12-08. Score: 12
Note how even for an if without an else there is some ambiguity:
if expression1 expression2;

Because where does expression1 end and expression2 begin? In C this ambiguity is resolved by requiring expression1 to be wrapped in parentheses. Rust does this the opposite way: expression2 must be wrapped in curly braces. The latter actually solves the ambiguity of the else clause. Consider this bad example in C:
if (foo)
   if (bar)
      baz();
else
   quux();

If you wrote something similar in Rust:
if foo {
    if bar {
        baz();
} else {
    quux();
}

It would be a syntax error, as there is a closing curly brace missing, and where you will put it will determine if the else-clause belongs to the inner or the outer if.
---
### Answer by username_7 on 2024-12-08. Score: 6
A simple solution is to require an end keyword. Then you can parse your expression easily, depending on the first keyword (if/for/etc) and optional arguments are covered because the end makes it distinct.
Then you can distinct between
if(condition)
    for(;;)
        body
    end
else
    fallback
end

and
if(condition)
    for(;;)
        body
    else
      fallback
    end
end

just by the different placement of the end keywords (thanks to @ChrisDodd for pointing this out).
Another example:
if x + if y then 1 else 2 end = 5 then for y in array do x+=y end end
> **Comments:**
> **username_8** (2024-12-10): Actually, if the `end` is *always* required (in a `for` statement as well as an `if`), it does solve the problem -- the placement of the `end` for the `for` determines whether the `else` binds to the `for` (`else` before `end`) or the `if` (`else` after then `end` for the `for`).  
> **username_7** (2024-12-10): @ChrisDodd oh, you are right! I missed that, I'll edit my answer accordingly.  
---
### Answer by username_5 on 2024-12-26. Score: 1
This is known as the dangling else problem and it can be formulated and resolved at different levels.
Level 1 is the syntactic level. We can avoid the problem syntactically; this is usually done by adding brackets of some kind. For instance, ALGOL 68 has
IF ...
THEN
  ...
FI

An ELSE part is optional.
Because the THEN and FI are required, the ...s may contain arbitrary sequences of statements, and arbitrary nested occurrences of this construct, without producing ambiguity.
ALGOL 68's ternary "operator" is simply IF ... THEN ... ELSE ... FI, i.e. the same construct (ALGOL 68 allows statements wherever expressions are allowed, and vice versa).
More languages use this approach, e.g. the Bourne shell.
An alternative is to require brackets around all sequences of statements/expressions. E.g. always require the brackets in if ( ... ) { ... }. Many languages do this.
You're asking: what if we don't. Many languages don't; for instance, C and Pascal.
This is level 2: our syntax doesn't protect us, so we need a defense at the semantic level.
The standard defense: precedence rules. We really don't care what the grammar for a * b + c * d looks like, but we disambiguate it using the precedence rule that * binds more strongly than +.
Similarly, we have precedence rules to disambiguate a ? b ? c : d, and if (a) b; c, and if (a) if (b) c else d, and whatever else. Users will need to look them up and apply them correctly every time, and if they're smart they will put in extra brackets anyway, but it is up to them, and as a consequence, lots of errors will still be made, because the language invites them.
Some programmers prefer this approach anyway. Not everyone is happy with Lisp syntax.
So now, I hear you ask, let's take for granted that our language is like this, and that programmers are like this, is there still something we can do? A level 3 defense?
Yes, there is: we can make our compiler (or a separate syntax checker) throw warnings whenever it meets a construct that looks like it may have a precedence error. We can even have several levels of verbosity and at the highest level have it ask for every construct that relies on a precedence rule whether the programmer meant to write that or the alternative. We can even have it insert brackets upon request.
This may be the best of both worlds: it allows the language to be permissive, while users and teams can still enforce non-permissive coding standards, even ones that completely eliminate all ambiguity.
---
