39

In various languages (Java at least, think also C#?) you can do things like

if( condition )
    singleStatement;

while( condition )
    singleStatement;

for( var; condition; increment )
    singleStatement;

So when I have just one statement, I don't need to add a new scope with { }. Why can't I do this with try-catch?

try
    singleStatement;
catch(Exception e)
    singleStatement;

Is there something special about try-catch which requires always having a new scope or something? And if so, couldn't the compiler fix that?

Svish
  • 1,102

4 Answers4

24

IMO, they're included in Java and C# primarily because they already existed in C++. The real question, then, is why is C++ that way. According to The Design and Evolution of C++ (ยง16.3):

The try keyword is completely redundant and so are the { } brackets except where multiple statements are actually used in a try-block or a handler. For example, it would have been trivial to allow:

int f()
{
    return g() catch(xxii) { // not C++
        error("G() goofed: xxii");
        return 22;
    };
}

However, I found this so difficult to explain that the redundancy was introduced to save support personnel from confused users.

Edit: As to why this would be confusing, I think one has only to look at the incorrect assertions in @Tom Jeffery's answer (and, especially, the number of up-votes it has received) to realize that there would be a problem. To the parser, this is really no different from matching elses with ifs -- lacking braces to force other grouping, all catch clauses would match up with the most recent throw. For those misbegotten languags that include it, finally clauses would do the same. From the viewpoint of the parser, this is hardly enough different from the current situation to notice -- in particular, as the grammars stand now, there's really nothing to group the catch clauses together -- the brackets group the statements controlled by the catch clauses, not the catch clauses themselves.

From the viewpoint of writing a parser, the difference is almost too tiny to notice. If we start with something like this:

simple_statement: /* won't try to cover all of this */
                ;

statement: compound_statement
         | simple_statement
         ;

statements: 
          | statements statement
          ;

compound_statement: '{' statements '}'

catch_arg: '(' argument ')'

Then the difference would be between:

try_clause: 'try' statement

and:

try_clause: 'try' compound_statement

Likewise, for catch clauses:

catch_clause: 'catch' catch_arg statement

vs.

catch_clause: 'catch' catch_arg compound_statement

The definition of a complete try/catch block would not need to change at all though. Either way it would be something like:

catch_clauses: 
             | catch_clauses catch_clause
             ;

try_block: try_clause catch_clauses [finally_clause]
         ;

[Here I'm using [whatever] to indicate something optional, and I'm leaving out the syntax for a finally_clause since I don't think it has any bearing on the question.]

Even if you don't try to follow all the Yacc-like grammar definition there, the point can be summarized fairly easily: that last statement (starting with try_block) is the one where catch clauses get matched up with try clauses -- and it remains exactly the same whether the braces are required or not.

To reiterate/summarize: the braces group together the statements controlled by the catchs, but do not group the catchs themselves. As such, those braces have absolutely no effect upon deciding which catch goes with which try. For the parser/compiler the task is equally easy (or difficult) either way. Despite this, @Tom's answer (and the number of up-votes it's received) provides ample demonstration of the fact that such a change would almost certainly confuse users.

Jerry Coffin
  • 44,795
19

In an answer about why brackets are required for some single-statement constructs but not others, Eric Lippert wrote:

There are a number of places where C# requires a braced block of statements rather than allowing a "naked" statement. They are:

  • the body of a method, constructor, destructor, property accessor, event accessor or indexer accessor.
  • the block of a try, catch, finally, checked, unchecked or unsafe region.
  • the block of a statement lambda or anonymous method
  • the block of an if or loop statement if the block directly contains a local variable declaration. (That is, "while (x != 10) int y = 123;" is illegal; you've got to brace the declaration.)

In each of these cases it would be possible to come up with an unambiguous grammar (or heuristics to disambiguate an ambiguous grammar) for the feature where a single unbraced statement is legal. But what would the point be? In each of those situations you are expecting to see multiple statements; single statements are the rare, unlikely case. It seems like it is not realy worth it to make the grammar unambiguous for these very unlikely cases.

In other words, it was more expensive for the compiler team to implement it than was justified, for the marginal benefit it would provide.

Robert Harvey
  • 200,592
13

I think it's to avoid dangling else style issues. The following would be ambiguous...

try
    // Do stuff
try
    // Do  more stuff
catch(MyException1 e1)
    // Handle fist exception
catch(MyException2 e2)
    // So which try does this catch belong to?
finally
    // and who does this finally block belong to?

It could mean this:

try {
   try {

   } catch(Exception e1) {

   } catch(Exception e2) {

   } 
} finally {

} 

Or...

try {
   try {

   } catch(Exception e1) {

   } 
} catch(Exception e2) {

} finally {

} 
Tom Jefferys
  • 303
  • 1
  • 4
1

I think the main reason is that there is very little you can do in C# that would need a try/catch block that is only one line. (I can't think of any right now of the top of my head). You may have a valid point in terms of the catch block, e.g a one line statement to log something but in terms of readability it makes more sense (at least to me) to require {}.

Jetti
  • 5,183