There are four broad approaches on how to put a block of code inside a control structure in a block-structured language.
The Algol Way
In the Algol way, each control structure has its own way to "close" the body. In Algol, specifically, you spell the opening word backwards:
IF 3 = input THEN
# Do something #
FI;
CASE input IN
~ # Do something, because input = 1 #
,
~ # Do something, because input = 2 #
,
~ # Do something, because input = 3 #
,
# fall through to the next statement IF there is no "OUT" #
OUT
~ # Do something ELSE. #
ESAC
Fortran uses something similar, using the keyword end
followed by the type of construct that it ends:
IF logical-expression THEN
statements-1
ELSE
statements-2
END IF
The Pascal Way
In the Pascal way, the body of a control structure is a single statement. Note that there is no "endif" token as part of the control structure's syntax:
if logical-expression then
single-statement-1
else
single-statement-2
However, a statement can be a block. In Pascal, blocks are denoted by begin
and end
. So the end
token delimits the block, not the if
statement which contains the block.
if logical-expression then
begin
statements-1
end
else
begin
statements-2
end
C also uses this syntax, but blocks are denoted by {
and }
.
if (logical-expression)
statement-1
else
statement-2
if (logical-expression) {
statements-1
} else {
statements-2
}
Note that C does not have a then
keyword, and so conditions are surrounded by parentheses to ensure that the condition is separate from the body.
The Perl Way
In C, the parentheses around the logical expression are not part of the expression's syntax, they are part of the control structure's syntax. Similarly, you can make the block begin/end markers part of the control structure. This is how Perl does it.
An if-then-else statement in Perl has this syntax:
if (logical-condition) {
statements-1
} else {
statements-2
}
Even if you only want a single statement in the body of an if-then-else, the braces must be included, because they are part of the if
statement's syntax. The same is true in Rust, where braces are a required part of the syntax for if
, while
and some other control-flow statements.
However, Perl does allow you to omit braces for a single statement if you use a "reversed" syntax:
# This IS NOT valid Perl
if (x < 2) do_something();
# This IS valid Perl.
do_something() if x < 2;
Perl's approach has a very counter-intuitive implication. Perl has the control statements next
, last
, and redo
which let you jump around a loop similar to break
in C.
while (<STDIN>) {
# This statement compares the line read from STDIN against
# the regular expression /^$/. If it matches, exit the loop.
last if /^$/;
statements
}
However, this last
keyword only applies to loops. You can't jump to the end of the body of a then:
if (x < 2) {
some statements
# The following statement jumps to the end of any
# enclosing loop, not to the end of the if statement.
last if y > 3;
some more statements
}
You can get the effect you want by naming a block:
LABEL: {
if (x < 2) {
some statements
# The following statement jumps to the end of the
# named block.
last LABEL if y > 3;
some more statements
}
}
However, in this case, you don't need the labels. A pair of curly braces that are not part of a control statement (i.e. just a block) has the semantics of a loop that executes exactly once. So either of these will also work:
# This outer pair of braces is, semantically, a run-once loop.
{
if (x < 2) {
some statements
# This statement jumps to the end of the enclosing loop.
last if y > 3;
some more statements
}
}
# The same as above, only the run-once loop is inside the "then" part.
if (x < 2) {{
some statements
last if y > 3;
some more statements
}}
I don't know of any other languages which have gone with Perl's approach. It seems a little difficult to explain.
The Occam Way
Occam uses whitespace to denote blocks.
IF
x > y
order := gt
x < y
order := lt
TRUE
order := eq
Python's syntax takes cues from Occam, but be aware that Python is not a block-structured language in the usual sense of that term; blocks are not variable scopes in Python.
End
is easier to type thanEndFunction
orEndStructure
. Another useful point of comparison might be HTML/XML, where each opening tag must be matched by a closing tag which includes the tag's name; I think many people don't like editing HTML or XML by hand, because it's so verbose. $\endgroup$\begin{foo}
…\end{foo}
. $\endgroup${
with eitherCtrl + Alt + B
orAltGr + B
. (AltGr is the right Alt key). And withN
for}
$\endgroup$