Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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?

share|improve this question

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
3  
as a side note D doesn't require braces around the single statement try catch blocks –  ratchet freak Nov 3 '11 at 14:07
12  
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

5 Answers 5

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.

share|improve this answer
    
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 2 days ago

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.

share|improve this answer

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 {

} 
share|improve this answer
21  
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

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 {}.

share|improve this answer

In terms of programming, try and catch clauses without braces - might just get very tricky or ambiguious for reasons that applies to for and if similarly. So by all means that would have been bad coding even if your language has allowed it.

But i believe your question was more of whether such a thing is a constraint for the programming language to provide or not?

If you know the relationship of stack with call hierarchies, you would

Digging into what is well known, every function call into the system does a PUSH in the stack and than POP back from the stack on the return. This is a fundamental reason why "local context" i.e. the scope of local variables (which are declared on stack) are no longer visible to levels below and above the stack context. When a regular function returns it gets back to original context on stack and functions normally. Here this is exactly one level above.

The try/throw/catch of C++ and the setjump/longjump of C both are a form of stack unwinding. When stack unwinding happens, longjump (or catch) allows functions to restore a condition to original point where setjump (or try) started and get back to the primary stack context, irrespective of the nested levels below.

So the implementation of try/throw/catch fundamentally involves the PUSH to stack and POP back from stack. Each such call is is equivalent to a function call nesting rather than a for loop rerun which remains inside the same stack context. So it is natural to assume that for language like C++ - it would have been really hard (if not impossible) to add the implied braces for try/catch while the same still doesn't remain necessary for for and if.

share|improve this answer
1  
try/catch did not evolve from setjmp/longjmp. They are similar in concept in that they walk up or down the stack, but exception handling is usually not implemented that way. Nor does it have anywhere close to similar semantics (longjmp won't destroy objects along the way...) –  Billy ONeal Nov 3 '11 at 15:05
    
@Billy: Neither does exception handling. If you're referring to RAII, that only works because the compiler adds implicit try/finally blocks to take care of object destruction. It's not some magical implicit property of exception handling. –  Mason Wheeler Nov 3 '11 at 16:48
    
@Mason: How can the compiler insert try/finally blocks in a language without finally blocks? –  Billy ONeal Nov 3 '11 at 16:52
1  
@Billy: Because RAII is an abstraction inversion. To be pedantic, it inserts constructs into the generated object code that would be called try/finally blocks in any language that supports try/finally blocks. –  Mason Wheeler Nov 3 '11 at 17:07
1  
@BillyONeal and MasonWheeler: You both seem to know more about the issue than some of the other answers. Instead of an extensive discussion here, it might be worthwhile posting an answer instead. –  Steven Jeuris Nov 3 '11 at 19:47

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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