38

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?

We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is right, ideally with citations. Answers that don't include explanations may be removed.

  • 3
    Nit-picking here: Strictly speaking for for the parts should be named something like initial, condition and step as initial need not define a variable and step need not be an increment. – Joachim Sauer Nov 3 '11 at 13:58
  • 4
    as a side note D doesn't require braces around the single statement try catch blocks – ratchet freak Nov 3 '11 at 14:07
  • 13
    I think the real question is the other way round: why do some constructs allow for "naked" statements? Braces should be compulsory everywhere for consistency. – UncleZeiv Nov 3 '11 at 18:51
  • 3
    @UncleZeiv - it's not inconsistent if you consider that what follows the if is always a single statement, and multiple statements enclosed by braces comprise a single statement. But I'm one of those who always put the braces in anyway, so... – detly Nov 4 '11 at 3:24
  • 1
    I tend to write the braces as well, but I like not having to write them when I have direct exit points like throw and return, and like @detly said, if you consider the braces as a single group of statements, I don't find it inconsistent either. I've never understood what these "lots of coding errors" mentioned by people are. People need to start paying attention to what they do, use proper indention and have unit tests :P never had a problem with this... – Svish Nov 4 '11 at 7:18
23

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.

  • The OP is asking about the brackets around both the try and the catch block, while this appears to be referencing those around the try (the first paragraph could be understood to reference both, but the code illustrates only the former)... Can you clarify? – Shog9 Nov 3 '11 at 18:27
  • @Mr.CRT: a "catch block" would otherwise be known as a "handler", about which see the quote above. – Jerry Coffin Nov 3 '11 at 18:32
  • 3
    bah, just edited my comment to remove that ambiguity. What I'm getting at is that this could be a more effective answer than Tom's (above) if it went to greater lengths to illustrate how the bracket-less construct could have worked, but in a confusing manner (Billy's comment on Tom's answer seems to imply that it could not have worked, which I believe is incorrect). – Shog9 Nov 3 '11 at 18:35
  • @JerryCoffin Thanks for expanding your answer: it's much clearer to me now. – user8 Nov 3 '11 at 20:30
  • try return g(); catch(xxii) error("G() goofed: xxii"); whould have been neat still IMO – alfC Dec 17 '14 at 1:55
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.

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 {

} 
  • 24
    This ambiguity applies to if and for equally. The question is : Why is it that it is allowed for if and switch statement but not for try/catch? – Dipan Mehta Nov 3 '11 at 14:49
  • 3
    @Dipan fair point. I wonder if it's simply a matter of Java/C# trying to be consistent with older languages such as C by allowing non-braced ifs. Whereas try/catch is a newer construct, therefore the language designers thought it ok to break with tradition. – Tom Jefferys Nov 3 '11 at 15:37
  • I tried answering the compulsion at least for C and C++. – Dipan Mehta Nov 3 '11 at 15:41
  • 6
    @DipanMehta: Because there are not multiple possible dangling else clauses for the if case. It's easy to just say "well the else binds to the innermost if" and be done with it. But for try/catch that doesn't work. – Billy ONeal Nov 3 '11 at 16:07
  • 2
    @Billy: I think you're glossing over the potential ambiguity present in if / if else... It's easy to say "it's easy to just say" - but that's because there's a hard rule for resolving the ambiguity that, incidentally, disallows certain constructs without the use of brackets. Jerry's answer implies this was a conscious choice made to avoid confusion, but surely it could have worked - just as it "works" for if / if else. – Shog9 Nov 3 '11 at 18:38
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 {}.

protected by gnat Oct 25 '17 at 11:40

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.