Why does Try-Catch require curly braces

C#Try Catch

C# Problem Overview


Just curious: Why is the syntax for try catch in C# (Java also?) hard coded for multiple statements? Why doesn't the language allow:

int i;
string s = DateTime.Now.Seconds % 2 == 1 ? "1" : "not 1";
try
   i = int.Parse(s);
catch
   i = 0;

The example is for trivial purposes only. I know there's int.TryParse.

C# Solutions


Solution 1 - C#

Consider the fact that there are really three (or more) code blocks in play here:

try {}
catch (myexcption)
{}
catch (myotherexception)
{}
finally
{}

Keep in mind that these are in the scope of a larger context and the exceptions not caught are potentually caught further up the stack.

Note that this is basically the same thing as a class construct that also has the {} structure.

Say for instance you might have:

try
try
if (iAmnotsane)
beatMe(please);
catch (Exception myexception)
catch (myotherexception)
logerror("howdy")
finally

NOW does that second catch belong to the first or the second try? What about the finally? SO you see the optional/multiple portions make the requirement.

Solution 2 - C#

UPDATE: This question was the subject of my blog on December 4th, 2012. There are a number of insightful comments on the blog that you might also be interested in. Thanks for the great question!


As others have noted, the proposed feature introduces ambiguities that are confusing. I was interested to see if there were any other justifications for the decision to not support the feature, so I checked the language design notes archive.

I see nothing in the language design notes archive that justifies this decision. As far as I know, C# does it that way because that's how other languages with similar syntax do it, and they do it that way because of the ambiguity problem.

I did learn something interesting though. In the initial design of C# there was no try-catch-finally! If you wanted a try with a catch and a finally then you had to write:

try
{
  try
  {
      XYZ();
  }
  catch(whatever)
  {
     DEF();
  }
}
finally
{
  ABC();
}

which, not surprisingly, is exactly how the compiler analyzes try-catch-finally; it just breaks it up into try-catch inside try-finally upon initial analysis and pretends that's what you said in the first place.

Solution 3 - C#

More or less, this is a play on the dangling else problem.

For example,

if( blah )
    if ( more blah )
        // do some blah
else
    // no blah I suppose

Without curly braces, the else is ambiguous because you don't know if it's associated with the first or second if statement. So you have to fallback on a compiler convention (e.g. in Pascal or C, the compiler assumes the dangling else is associated with the closest if statement) to resolve the ambiguity, or fail the compile entirely if you don't want to allow such ambiguity in the first place.

Similarly,

try
    try
        // some code that throws!
catch(some blah)
    // which try block are we catching???
catch(more blah )
    // not so sure...
finally
    // totally unclear what try this is associated with.

You could solve it with a convention, where catch blocks are always associated with the closest try, but I find this solution generally allows programmers to write code that is potentially dangerous. For example, in C, this:

if( blah )
    if( more blah )
        x = blah;
    else
        x = blahblah;

...is how the compiler would interpret this if/if/else block. However, it's also perfectly legitimate to screw up your indenting and write:

if( blah )
    if( more blah )
        x = blah;
else
    x = blahblah;

...which now makes it appear like the else is associated with the outer if statement, when in fact it is associated with the inner if statement due to C conventions. So I think requiring the braces goes a long way towards resolving ambiguity and preventing a rather sneaky bug (these sorts of issues can be trivial to miss, even during code inspection). Languages like python don't have this issue since indentation and whitespace matter.

Solution 4 - C#

If you assume that the designers of C# simply choose to use the same syntax as C++ then the question becomes why are braces necessary with single statements try and catch blocks in C++. The simple answer is that Bjarne Stroustrup thought the syntax was easier to explain.

In The Design and Evolution of C++ Stroustrup writes:

"The try keyword is completely redundant and so are the { } braces except where multiple statements are actually used in a try-block or a handler."

He goes on to give an example where the try keyword and { } are not needed. He then writes:

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

Reference: Stroustrup, Bjarne (1994). The Design and Evolution of C++. Addison-Wesley.

Solution 5 - C#

The first think I can think of is that the curly braces create a block with its own variable scope.

Look at the following code

try
{
    int foo = 2;
}
catch (Exception)
{
    Console.WriteLine(foo); // The name 'foo' does not exist in the current context
}

foo is not accessible in the catch block due to the variable scoping. I think this makes it easier to reason about whether an variable has been initialized before use or not.

Compare with this code

int foo;
try
{
    foo = 2;
}
catch (Exception)
{
    Console.WriteLine(foo); // Use of unassigned local variable 'foo'
}

here you can not guarantee that foo is initialized.

Solution 6 - C#

try // 1
try // 2
  something();
catch { // A
}
catch { // B
}
catch { // C
}

does B catches try 1 or 2?

I don't think you can resolve this unambiguously, since the snippet might mean:

try // 1
{
    try // 2
        something();
    catch { // A
    }
}
catch { // B
}
catch { // C
}


try // 1
{
    try // 2
        something();
    catch { // A
    }
    catch { // B
    }
}
catch { // C
}

Solution 7 - C#

The rational is that it's more maintainable (easier to change, less likely to break, ergo higher quality):

  1. it's clearer, and
  2. it's easier to change because if you need to add a line to your blocks you don't introduce a bug.

As to why exception handling is different than conditional expressions...

  • If/Else is conditional upon an expression to use one of two (or more If/Else if/Else) paths in the code
  • Try/Catch is part of exception handling, it is not a conditional expression. Try/Catch/Finally operates only when an exception has been thrown inside the scope of the Try block.

Exception handling will traverse up the stack/scope until it finds a Catch block that will catch the type of exception that was thrown. Forcing scope identifiers makes this check for blocks simplified. Forcing you to scope when dealing with exceptions seems like a good idea, it also is a good indication that this is part of exception handling rather than normal code. Exceptions are exceptions, not something you really want happening normally but know can happen and want to handle when they do happen.

EDIT: There is one more reason which I can think of, is that CATCH is mandatory after a TRY unlike ELSE. Hence there needs to be definite way to define the TRY block.

Solution 8 - C#

Probably to discourage overuse. A try-catch block is big and ugly, and you're going to notice when you're using it. This mirrors the effect that a catch has on your application's performance - catching an exception is extremely slow compared to a simple boolean test.

In general you should avoid errors, not handle them. In the example you give, a much more efficient method would be to use

if(!int.TryParse(s, out i))
 i=0;

Solution 9 - C#

Another way of looking at this…

Given all the maintenance problem that have been created by “if”, “while”, “for” and “foreach” statements without bases, a lot of companies have coding standards that always require bases on statements that act on a “block”.

So they make you write:

if (itIsSo)
{
ASingleLineOfCode();
}

Rather then:

if (itIsSo)
ASingleLineOfCode();

(Note as indenting is not checked by the compiler, it can't be depended on to be right)

A good case could be made for designing a language that always require the bases, but then too many people would have hated C# due to having to always use the bases. However for try/catch there was not an expectation of being able to get away without using the bases, so it was possible to require them without to many people complaining.


Given a choose I would much rather have if/endIf (and while/endWhile) as the block delimiters but the USA got its way on that one. (C got to define what most languages look like rather than Module2, afterall most of what we do is defined by history not logic)

Solution 10 - C#

The simplest (I think) answer is that each block of code in C/C++/C# requires curly braces.

EDIT #1

In response to negative votes, directly from MSDN:

>try-catch (C# Reference) > >The try-catch statement consists of a try block followed by one or more catch clauses, which specify handlers for different exceptions.

As per definition says, it is a block, so it requires curly braces. That is why we cannot use it without { }.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShlomoView Question on Stackoverflow
Solution 1 - C#Mark SchultheissView Answer on Stackoverflow
Solution 2 - C#Eric LippertView Answer on Stackoverflow
Solution 3 - C#kidjanView Answer on Stackoverflow
Solution 4 - C#user9182View Answer on Stackoverflow
Solution 5 - C#Albin SunnanboView Answer on Stackoverflow
Solution 6 - C#THX-1138View Answer on Stackoverflow
Solution 7 - C#Sachin ShanbhagView Answer on Stackoverflow
Solution 8 - C#JakeView Answer on Stackoverflow
Solution 9 - C#Ian RingroseView Answer on Stackoverflow
Solution 10 - C#Will MarcouillerView Answer on Stackoverflow