2

When throwing an exception preserving the stack trace is the most common desired behavior, and in Java this can be obtained with throw ex;, but in C# throw; must be used. (Please also notice that many of C# programmers will often wrongly use throw ex; instead of throw;).

If sometime the stack trace must be cleared (which is a less frequent situation), it is possible to just throw a new exception like throw new MyException(ex.Message, otherDetails);.

So, considering the above, which is the advantage of having a separate throw; statement in C#?

Or, in other words: why is C# using a special separate statement (throw;), which is less known, for the most used case (when the user wants to preserve the stacktrace), and it uses the more natural throw ex; for the less frequent case (when the stacktrace is cleared)? Is there any other possible use case for which I didn't cover?

Code sample in C# and Java:

// This is the C# design
try
{
//...
}
catch (MyException ex)
{
   // rethrow so that stack trace is preserved
   ex.AppendData(contextVariable);
   throw;
}
catch (PrivateException ex)
{
   // throw new exception so stack trace is not preserved
   throw new PublicException(ex.Message);
}


// This is the Java design
try
{
//...
}
catch (MyException ex)
{
   // rethrow so that stack trace is preserved
   ex.AppendData(contextVariable);
   throw ex;
   // and I can even choose to use something like, where ProcessException(ex) will return the same ex
   throw ProcessException(ex, contextVariable);
}
catch (PrivateException ex)
{
   // throw new so stack trace is not preserved
   throw new PublicException(ex.getMessage());
}
Andrei Bozantan
  • 3,781
  • 2
  • 30
  • 40
  • Seems pretty strange to be asking about a language design feature that has been there since C# version 1. – John Saunders Jun 16 '14 at 18:13
  • @JohnSaunders although the feature is form C# version 1, I still do not understand the reasons behind it. – Andrei Bozantan Jun 16 '14 at 18:15
  • 2
    Please check out http://stackoverflow.com/questions/730250/is-there-a-difference-between-throw-and-throw-ex?rq=1 (which I believe completely covers portion of your question that is not non-opion based or historical research). Feel free to ask new question clearly specifying what problem you stuck with understanding the behavior. – Alexei Levenkov Jun 16 '14 at 18:17
  • For historical research please make sure to find and read corresponding blogs on http://blogs.msdn.com and add finding to question. Note that historical research questions generally too broad, so make sure to show good reasons why your one need to stay. – Alexei Levenkov Jun 16 '14 at 18:19
  • @AlexeiLevenkov This question is not a duplicate. The other question asks which is the difference, but I am asking why there is a need for two different statements. If this is opinion based, where should I ask it? I still find plenty of other opinion based questions on stackoverflow which are not closed and I think that opinion based answers are valuable for better understanding different topics. – Andrei Bozantan Jun 16 '14 at 18:27
  • "I think that the throw; is unnatural," - is opinion based part, try to avoid such comments in your post... "Why particular design decision was made long time ago" is generally of low practical value so SO is not the right place. Check rules of http://programmers.stackexchange.com and see if it fits there. – Alexei Levenkov Jun 16 '14 at 18:34
  • @AlexeiLevenkov can you please remove the duplicate tag, since as I explained, this is not a duplicate and I reformulated the question so that is not opinion based. – Andrei Bozantan Jun 16 '14 at 18:44
  • I agree that this is not a duplicate, but I'm not sure there's any point in reopening it as it will be closed for a different reason – Ben Aaronson Jun 16 '14 at 18:45
  • @BenAaronson at least it should be closed for the correct reason; if it is marked at duplicate there is no chance that someone who could really answer this question will take a look at it. – Andrei Bozantan Jun 16 '14 at 18:49
  • Removing duplicate and seeking for better (if any) close reason - http://meta.stackoverflow.com/questions/260711/should-why-language-feature-designed-particular-way-be-closed-moved – Alexei Levenkov Jun 16 '14 at 19:58
  • `throw ex;` would be ambiguous. It would require the CLR to compare the current context of the exception with the one being thrown to determine if the stacktrace should change. As someone could always `throw new NameSpaceException(ex);` wrapping the thrown exception. – Erik Philips Jun 16 '14 at 20:07
  • @ErikPhilips Exactly. It is allowed to write code like `catch (Exception ex) { if (DateTime.Today.DayOfWeek == DayOfWeek.Thursday) { ex = new InvalidOperation(); } if (randomNumberGenerator.Next(2) == 0) { ex.HelpLink = "http://hello.mum/"; } throw ex; }`. – Jeppe Stig Nielsen Jun 16 '14 at 20:11

2 Answers2

3

The reason that both throw variants in

catch (SomeExceptionType ex)
{
    frobnicate(ex);
    throw;
    throw ex;
}

exist is because there are use cases for each. Only the first is useful for debugging the code where the exception occurred, but in a mature library, it is almost certain the cause was external to the library (either failure in the hardware/operating system environment, or bad parameter passed by the consumer of the library). In such cases, details of the library innards are not helpful to the programmer using the library, and may in fact cause more confusion.

Furthermore, a closed-source library, especially one accessed remotely in a SaaS model1 (webservice) may not want to expose implementation details, since these can contain proprietary intellectual property. In such cases, throw ex; is preferable.

You say that Java throw ex; preserves the existing stack trace. How can information leakage be avoided with such a language? One must make a deep copy of everything but the stack trace to a new exception object, which is particularly difficult when exceptions of more derived types are thrown. The C# choice makes both behaviors very easy to obtain.

(You might still want to perform a filtered deep copy, in case information is leaked in other exception properties, such as InnerException. But C# lets you skip the copy step if you so choose.)

1 Implementation details of a local library can be discovered in other ways. Protection of those details requires a webservice-like execution model, where complete control over the code is maintained.

Community
  • 1
  • 1
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 1
    Why would you `throw` instead of merely allowing the original exception to go up the call stack? – Robert Harvey Jun 16 '14 at 20:13
  • @RobertHarvey: For logging purposes? – Victor Zakharov Jun 16 '14 at 20:14
  • I would think that 'throw' is useful when you catch one or more specific exceptions to handle and throw anything else up. – Doug Dawson Jun 16 '14 at 20:15
  • @RobertHarvey: Maybe you're going to do so conditionally, and the condition involves more than just type information. Maybe you're doing other things in the handler before rethrowing. The code snippet is intended to show the context, not be an actual usable piece of code (the second throw is unreachable anyway) – Ben Voigt Jun 16 '14 at 20:16
  • @RobertHarvey I want to catch an exception, add some context information to it (which is easily available at this point) and then let it go up the call stack. – Andrei Bozantan Jun 17 '14 at 09:11
2

The semantics of the throw expression; statement are different in C# and Java. In Java, the exception stack trace is captured at the time the exception object is instantiated. In C#, the exception stack trace is captured at the time the exception object is thrown.

In addition, the CLI (ECMA-335) provides a special bytecode instruction rethrow which differs from throw in two primary ways:

  1. The exception which is thrown by rethrow is the same exception instance that is currently being handled.
  2. The rethrow instruction preserves the original stack trace.

These semantic differences require C# to either provide two different forms for throwing exceptions, or remove the ability of C# users to be able to preserve the original exception stack trace during an intended rethrow operation (not to be confused with the rethrow bytecode instruction, which is specifically made accessible by the throw; syntax).

Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
  • Or remove the option to NOT preserve the original stack trace. – Ben Voigt Jun 16 '14 at 20:11
  • 1
    @BenVoigt That would require writing the C# specification in such a way that the behavior of `throw expression;` depends on *both* the form of `expression` and whether the statement appears inside a `catch` block or not. What happens if you have `catch (Exception e) { var e2 = e; throw e2; }`? – Sam Harwell Jun 16 '14 at 20:15
  • Not really. Just `if (the specified Exception object has never been thrown) capture new stack trace; else rethrow;` It would help with Task-like exception propagation as well. – Ben Voigt Jun 16 '14 at 20:19
  • To be clear, I like the existing design. But I don't like false dichotomy. – Ben Voigt Jun 16 '14 at 20:26
  • @BenVoigt it may seem as easy as that, but it have already been thrown in another thread, or domain as passed back to the current thread or domain. – Erik Philips Jun 16 '14 at 20:26
  • @Erik: Yes it might have. That's actually an advantage to the hypothetical behavior. For example, `async`/`await` forward (in some sense) exceptions across threads. – Ben Voigt Jun 16 '14 at 20:26
  • My own opinion is that because `throw;` can only be used in a `catch` it's only a dichotomy in `catch`, which really means that the context defines the behavior and it actually makes sense. – Erik Philips Jun 16 '14 at 20:28