In C, else if
is nothing but a new if
statement after a single-statement else
clause. Why do languages like Python and Ruby have a dedicated construct for elsif
/elif
?
6 Answers
They do this to avoid the dangling else problem.
In many programming languages, the syntax for else-if statements is ambiguous. For example, consider the following C program:
if(a) if (b) x++; else y++;
Which if
should the else belong to? Is it the inner one?
if (a)
if (b)
x++;
else
y++;
or the outer one?
if (a)
if (b)
x++;
else
y++;
This ambiguity is known as the "dangling else problem". One way that programming languages can avoid it is to require delimiters around the "then" and the "else" part of the if
. Some languages, such as Swift, mandate that there must be curly braces:
if (a) {
x++;
} else {
y++;
}
Some languages instead use then
and end
keywords, for a similar effect. For example, Lua:
if a then
x = x + 1
else
y = y + 1
end
However, if our language requires these delimiters around the else
then we cannot write else if
as we do in C. Because else
must be followed by an open curly brace, we would end up with open braces between the else
and the if
, and a long sequence of closing delimiters at the end.
if (a) {
x++;
} else { if (b) {
y++;
} else { if (c) {
z++;
} else {
w++;
}}} /*ouch!*/
Having an elseif
keyword is an elegant way to avoid this }}}
avalanche. We can still mandate braces after if
and else
, but there aren't those pesky braces between the two
Swift and Rust avoid the else { if
problem by special casing the else if
. Their grammar says that the next token after the else
must be a {
, unless it's an if
. This is certainly a valid way to solve the problem and avoids creating a new keyword. That said, the programmer must be aware that else if
is a special case. If one is used to languages with traditional if-else syntax, they might expect they are allowed to write to substitute any other statement in place of the if
statement in the else if
. In languages with elseif
this question doesn't come up because it's loud and clear that elseif
is special.
-
1$\begingroup$ PHP is a clike just like C and JS, and it has
elseif
. I wonder what the reason is there, maybe to save the keystroke. $\endgroup$– naffetSCommented May 19, 2023 at 3:23 -
7$\begingroup$ The dangling
else
problem doesn't contain any occurrences ofelse if
, and would still occur in C's grammar ifelseif
were to be written instead. The point about block delimiters is reasonable, but I think it would be clearer if this answer said that it's a consequence of requiring delimiters aroundif
andelse
blocks, which is done in part to avoid the danglingelse
problem but also for other reasons (hence such languages also tend to require block delimiters for loops, try/catch, and so on). $\endgroup$– kaya3Commented May 19, 2023 at 9:58 -
2$\begingroup$ Also technically the dangling
else
problem could also be solved by only requiring braces around theif
body, and not necessarily also theelse
body, which would allowelse if
to still be written. Though this might seem inconsistent to users of the language. $\endgroup$– kaya3Commented May 19, 2023 at 10:00 -
5$\begingroup$ In Python, the dangling else problem is avoided by significant indentation, which is analogous to mandating braces around the if/else body. Python's elif allows if-else-if without having to nest the elses in increasingly deeper levels of indentation (which would be analogous to the
}}}
problem discussed in my answer). $\endgroup$– hugomgCommented Jul 2, 2023 at 14:25 -
2$\begingroup$ More specifically, the programmer is likely to write the second version, and their use of indentation may think it will work as they expect, but it will actually be parsed as the first version. This is similar to what happens when they write a braceless
if
orelse
and later add a second statement without adding braces. $\endgroup$– BarmarCommented Feb 20 at 21:22
The way the chaining of else if
blocks is defined in C follows naturally from the way the grammar allows for braceless blocks:
if (x) {
} else if (y) {
}
being parsed the same as
if (x) {
} else
if (y) {
}
i.e.
if (x) {
} else {
if (y) {
}
}
When you allow for such constructs in the syntax, a dedicated keyword is useless.
On the other hand, if you take Python, for example, since blocks are defined by indentation (and not by enclosing tokens such as braces), this is not valid out-of-the-box (you have to special-case it, whereas in C it was "free"):
if x:
pass
else if y:
pass
So, given that we're forced to create that special case, it makes sense to choose something shorter than else if
, hence elif
(or elsif
).
Another reason for elseif/elsif/elif
is if the conditional construct has a keyword terminator, like the shell's fi
or Lua's end
. You don't want to be writing else if
because now you're writing nested if
's, which have to be terminated with a whole sequence of repeated end
tokens.
-
$\begingroup$ That is the reason I added
ElseIf
to AEC (my programming language). $\endgroup$ Commented Jul 4, 2023 at 13:32
They need one
In C-style languages like JS, you can put a single statement after an if
to run just that one:
if (x == 1) print("x is 1!");
In fact, else if
isn't even necessarily interpreted specially by the compiler. It could just be parsed as an if
statement directly following the else
.
However, in languages like Python where you can't do this, it would be natural to have a keyword specifically for else-if since you don't get that for free.
-
2$\begingroup$ There are languages that have "else if" as separate words but do not allow a single expression after
if
(like Rust) $\endgroup$ Commented May 16, 2023 at 17:25 -
$\begingroup$ @mousetail That's true, I was going to touch on how it's possible to detect an
else if
even without that, might come back and do that in a sec $\endgroup$– rydwolfCommented May 16, 2023 at 18:06
else if
could never be an invalid construct in any reasonable language.
Languages that also use elseif
tend to have enforced grouping constructs. That is, you cannot omit the braces or equivalents after the if
conditions. In many cases it's because the language is using specific grouping constructs for every control structure, that is, if
...endif
, for
...endfor
. In other cases it's because grouping is an important part of the grammar, for example in Python and Tcl.
In these cases, if you don't use elseif
, a long conditional statement would become:
if(...)
...;
else
if(...)
...;
else
if(...)
...;
else
...;
endif;
endif;
endif;
which stacks many endif
s at the end and is not very practical.
There are languages like PHP, where grouping constructs are not enforced, but also have elseif
. Many people choose to use else if
anyway, and some may not even realize elseif
existed. So your design decisions may not matter that much, after all.
There are also languages like the LISP variants. Everybody already knows that code in them would always have this problem everywhere, so nobody cares about the little more problems caused by not having elseif
with enforced grouping constructs.
-
$\begingroup$ There are much terser ways to write
if
-else
-chains than by adding theelif
keyword. Even in C you'd write something likea?b:c?d:e?…
. $\endgroup$ Commented Feb 19 at 18:53