Avoiding the 'dangling else' language problem with mandatory block markers

March 22, 2020

There is a famous parsing ambiguity in many programming languages known as the dangling else, where it's ambiguous which 'if' statement an 'else' is associated with. In C, for example, you can write:

if (a)
if (b)
   res = 10;
else
   res = 20;

Which if the else is associated with is somewhat ambiguous; is it the first or the second? (C provides an answer, as any language that allows this must.)

It's recently struck me that one way to avoid this in language design is to require some form of explicit block markers for the statements inside an if (and an else). In C terms, to disallow bare statements after if and else and always require '{' and '}'.

Go takes this approach with explicit block markers. In Go, an if requires a delimited block, not a bare statement, and else is similarly unambiguous. A lot of things in Go require blocks, in fact. Python also does this through its implicit blocks that are created through indentation; which if an else is associated with is both visually and syntactically unambiguous.

(Python allows writing simple 'if' clauses on one line, but not ones that involve nested ifs, and then you have to put the else on the next line.)

Another Unix language that avoids this ambiguity is the Bourne shell. Although we don't necessarily think about it all that often, the 'then' and 'fi' in Bourne shell if expressions are block markers, and they're mandatory:

if [ -x /usr/bin/something ]; then
  ...
fi

Although you can write this all on a single line, you can't leave out the markers. This is actually a somewhat tricky case, because 'else' is a peer with these two markers; however, the result isn't ambiguous:

if [ -x /something ]; then
if [ -x /otherthing ]; then
...
else
....
fi
fi

Since we haven't seen a 'fi', the 'else' has to be associated with the second 'if' instead of the first.


Comments on this page:

From 78.58.206.110 at 2020-03-22 07:17:11:

Unfortunately, some people still find ways to write ugly code despite then..fi being mandatory... What's the longest chain of [ this ] && that || something && whatever that you've seen in a shellscript?

When it comes to abusing deeply nested ternary operators, at least C has the advantage of being read entirely left-to-right, while Python is (without any parens to help you) inside-out.

By loreb at 2020-03-22 13:45:16:

Speaking of unix languages, perl does the same:

if(...) doit(); # syntax error
if(...) { doit(); } # good
doit() if ...; # also good
Written on 22 March 2020.
« Wishing for a remote resilient server environment (now that it's too late)
Why we use 1U servers, and the two sides of them »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sun Mar 22 02:35:23 2020
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.