Overv
Overv

Reputation: 8529

Why are curly braces in functions not optional in C-style languages?

The language designers have chosen to make the curly braces in the following scenarios optional:

if (a)
    b
while (a)
    b
...

Why is the same not allowed in functions, like this?

int add(int a, int b)
    return a + b;

Upvotes: 21

Views: 3290

Answers (6)

Waji Deus
Waji Deus

Reputation: 49

I know this is like, a 7 year bump, but all of the above answers are incorrect; though Robert Cooper is right when he says it would break the grammar.

The real problem has to do with how the original version of C looked:

main(argc, argv)
    char *argv[];
{
    puts("hello world!");
}

Everything in C was an int by default, so much of the type annotation could be omitted. Modern C is fully backwards compatible with this because people didn't want to throw out or update a bunch of existing code.

Note that the type annotation that comes after the function parameter list looks exactly like a normal variable declaration. This was done intentionally, probably to simplify the original grammar, but would mean that trying to define a function without curly braces like in your example would be completely ambiguous.

Basically, it can't work because, the parser can't tell the difference between a declaration statement and type annotation.

Upvotes: 2

Robert Cooper
Robert Cooper

Reputation: 1270

I'm sure this would mess up the grammar. For example there would be no difference between this empty function definition...

void empty()
{
    ;
}

...and this function declaration:

void empty();

Upvotes: 30

bit-twiddler
bit-twiddler

Reputation: 111

Curly braces are not optional components of the "if" and "if-else" control statements. The grammatical production for the "if" control statement allows one nonterminal symbol to follow the expression. The grammatical production for the "if-else" control statement allows one nonterminal symbol to follow the expression and one nonterminal symbol to follow the "else" terminal symbol. The name of that nonterminal symbol is <statement>.

In the context of the control structures (a.k.a. control statements), the curly braces belong to a language nonterminal symbol known as <compound-statement> (sometimes referred to as <block>). The non-terminal symbol <compound-statement> appears on the right-hand side of the <statement> grammatical production, which is why the curly braces can be used with the "if" and "if-else" control statements (i.e., a compound statement is a statement).

<statement> ::= <if-then-statement> | 
                <if-then-else-statement> | 
                <for-statement> |
                <do-while-statement> |
                ...
                <compound-statement>

<statement-list> ::=  <statement> | <statement-list> <statement> 

<if-then-statement> ::= "if" "(" <expression> ")" <statement> 

<if-then-else statement> ::= "if" "(" <expression> ")" <statement> 'else' <statement>

<compound-statement> ::= "{" <statement-list> "}"

With respect to function declarations, the <compound-statement> nonterminal symbol is the last nonterminal symbol on the right-hand side of the <function-declaration> grammatical production.

P.S. All nonterminal symbols are grammatical productions. All grammatical productions reduce to one or more nonterminal and/or terminal symbols. Terminal symbols are language keywords.

Upvotes: 1

Mihai Stancu
Mihai Stancu

Reputation: 16107

There is no fixed keyword related to function definitions. With if/else/for/while/switch there is one such keyword that marks the beginning of the logic-control structure.

Even though context allows us humans to discern how come int some_name (some_expression) some_other_expressions; is a function - in programming practice (although doable unambiguously) it takes a lot of backtracking to make sure 3-4-6 symbols ahead in the token-stream nothing changes this from a function declaration to something else.

A programming language parser can be classified by it's approach to parsing, either it takes the current token in the token list and checks if the next token confirms "this is an if" or "this is a function" or it takes a maximum look-ahead tokens (2-3-6?) and confirms "this could be a function", "now that i see the 5th token this is surely a function" or it uses backtracking with a variable look-ahead approach that goes as far ahead in the token list as needed to make sure the construct we are studying is something not something else.

Upvotes: 3

Peter Ruderman
Peter Ruderman

Reputation: 12485

I'm not sure that they did "choose" this. Rather, the ability ommit curly braces for if, while, for, etc. emerges as a natural consequence of the way they specified the grammar. The grammer forbids it for functions probably because of the old-style function declarations.

Upvotes: 6

Armen Tsirunyan
Armen Tsirunyan

Reputation: 132994

If I were to speculate, I'd say that it's because a function normally contains more than one statement whereas an if or while statement often contains only one statement. Also, it proved to be long-sighted inasmuch as in C++ allowing the ommission of {} would lead to ambiguities in member functions. For example:

struct s
{
     void f() const int i; //does const refer to int i or the function?
}

Upvotes: 2

Related Questions