try { ... } fault { ... }

Topics: C# Language Design
Apr 8, 2014 at 7:09 PM
Edited Apr 8, 2014 at 7:11 PM
The CLR has a feature, called fault blocks, which is just like finally blocks, except that the block only executes in case of an exception (any exception).

We would like this feature in C#. For example:
try
{
    SomeCode();
    Transaction.Commit();
}
fault
{
    Transaction.Rollback();
}
Apr 8, 2014 at 8:50 PM
I know it's pre-heated topic, so pls don't throw big stones @ me, throw small ones :)

First of all, please amend your sample to reflect the problem better. Currently this code is exactly what you are asking:
try
{
    SomeCode();
    Transaction.Commit();
}
catch
{
    Transaction.Rollback();
    throw;
}
I guess you are talking about this kind of scenario (using C# 5 syntax):
try
{
    try
    {
        /* Business logic is here */
    }
    catch (BusinessException1 e1)
    {
        if (e1.Status == 42)
            return;
        // Otherwise handle e1
        throw;
    }
    catch (BusinessException2 e2)
    {
        // Handle e2
        throw;
    }
}
catch
{
    // global processing
    throw;
}
If I understand correctly, your want to reduce outer try-catch to fault in internal try-catch?
Apr 9, 2014 at 10:03 AM
Edited Apr 9, 2014 at 10:03 AM
Yes this is one way to emulate it, although it's quite ugly.
Note that it is not exactly the same: the way exceptions raised inside the internal catch clauses are handled is different (they would be outside the real fault block).

I like to do that, which I think is simpler and doesn't handle exceptions inside catch blocks:
bool success = false;
try
{
  // Do stuff
  success = true;  // at the end.
}
catch (WhateverException)
{
}
finally
{
   if (!success) HandleFaults();
}
The problem with this is that the success flag may be tedious to set to true if there multiple exit paths (e.g. return statements inside the try).
Apr 9, 2014 at 3:43 PM
Edited Apr 9, 2014 at 3:44 PM
I'd feel more for Java 8 exception catching:
catch (IOException|SQLException ex) {
    logger.log(ex);
    throw ex;
 }
See also: http://docs.oracle.com/javase/tutorial/essential/exceptions/catch.html
Apr 9, 2014 at 10:09 PM
What I'd like to see would be finally (Exception ex) { ... finally code here }, with ex being null when no exception is thrown. Additionally, I'd like to see using enhanced so that if an object supports an interface IDisposableEx or IDisposableExOnly, the generated code for the finally would pass the exception argument to IDisposableEx.Dispose.

Those changes would allow for at least three major improvements in exception handling:
  1. It would be possible to properly handle exceptions which occur within a "finally" block. Without the above feature, or the ability to use exception filters to capture a pending exception, an exception which occurs within finally must either be stifled (letting code erroneously think everything fine when it isn't), or must destroy any previously-pending exception. If the finally block knows what exception was pending when it is entered, it can include that exception within any exceptions that occur within the finally block itself.
  2. If a finally block (or using-block Dispose) is reached without something having happened that should have and no exception is pending, an exception should be thrown to flag the incorrect usage. If, however, the reason the proper action didn't occur is that the block was exit via an exception, throwing an exception and obliterating the earlier one would be exceptionally rude. Letting the finally-block code or Dispose know whether an exception was pending would allow proper behavior in both cases.
  3. If an exception is thrown in a block of code that e.g. has a reader-writer lock open for writing, the proper behavior should often not be to release the lock, nor to exit while it's held, but rather to expressly invalidate it so that any future attempt to wait on it will fail immediately (as opposed to waiting forever). The code required to implement this in the absence of the proposed feature would be rather clunky; with the proposed feature, it would be much more compact.
The idea that exception-handling code is rare has become widespread, but unfortunately fails to distinguish between reacting to an exception versus resolving it. Normal practice when an exception causes an unanticipated execution path should be to expressly invalidate anything that may have become corrupted as a result. If such practice were commonplace, code could distinguish situations where a critical system object got corrupted (and where the system shouldn't continue running) from those where corruption is limited to objects that will be abandoned as a result of stack unwinding (where the system should continue running, recognizing that a request to do something couldn't be completed). The idea that one can't possibly hope to properly handle an unanticipated exception is nonsense: there are many situations where 99% of possible unanticipated exceptions could be best handled handled the same way as anticipated ones; having exceptions expressly invalidate possibly-corrupted data structures would help code to discover the remaining 1%.
Apr 10, 2014 at 8:05 PM
I am a much bigger fan of fault than finally(Exception)

I also really like the idea of catch (IOException|SQLException ex) {

While neither of these are commonly occurring, when they do occur, the code you write just sucks badly.
Coordinator
Apr 14, 2014 at 8:21 PM
Exception filters do help with some of the scenarios here, though maybe not as directly as you would like.
catch (IOException|SQLException ex)
{ ... }
This one raises the question of what the type of ex is in the catch body. With exception filters you can say it like this:
catch (Exception ex) if (ex is IOException || ex is SQLException)
{ ... }
A bit more verbose, but very general and you get to (and have to) explicitly specify the type of ex.

Exception filters can also improve on the success approach to fault blocks that @jods posted above. The problem there was making sure you set success = true on all successful branches. But instead you can turn it around and say this:
bool success = true;
try
{
  // Do stuff
}
catch (WhateverException)
{
}
catch (Exception) if (success = false) {} //set success to false if any exception comes through here
finally
{
   if (!success) HandleFaults();
}
It's a bit of a sneaky trick to use the false value both to signal to the finally block and to filter out the exception. But it's nicely localized.
Apr 15, 2014 at 7:00 AM
@madst:
  1. Is that really working? If the try block throws WhateverException, does the filter for Exception really run? Usually you don't use side-effects inside exception filters, so it doesn't matter and I haven't really thought about it before. But now that I see it, I find it highly unexpected (I know the CLR defines this behavior and it can't be changed now). My expectation would be that when unwinding the stack, the CLR finds the catch (WhateverException) first and is satisfied by this, without ever looking at the catch if after it.
  2. If it works, that is a neat trick but very ugly. Using an assignment = inside a if is always highly frown upon where I work.
Still wishing fault would complement finally...
Apr 15, 2014 at 3:28 PM
I also really like the idea of catch (IOException|SQLException ex) {
 
Would it make sense to mention .NET's AggregateException class in response to Java's approach?
Apr 15, 2014 at 11:58 PM
jods wrote:> 2. If it works, that is a neat trick but very ugly. Using an assignment = inside a if is always highly frown upon where I work.

The approach does work in vb, and I see no reason it wouldn't work in C# if it provided exception filters, but would much rather see the language hide the ugliness and simply provide a finally (Exception ex) { ... } block and have using blocks call IDisposableExOnly.Dispose(Exception Ex) or IDisposableEx.Dispose(Exception Ex) for types implementing one of those interfaces [I'd have IDisposableEx inherit from both IDisposableExOnly and IDisposable].
Apr 16, 2014 at 9:07 AM
@supercat: Would you care to explain how the hack shown by mads would work with VB.NET exception filters?
Catch ex As Exception When success = False
is not an assignment in VB.NET, just a comparison.

Maybe you missed that the C# hack suggested by mads has two effects: 1. the exception filter always evaluates to false; 2. but it also sets the success flag to false for future handling in finally.
Apr 16, 2014 at 9:40 AM
Visual Basic is a read only language for me, but I think you'd need something like this:
Sub Main
    
    Dim exceptionCaught As Boolean = False
    
    Try
        Throw New Exception("test")
    Catch ex As Exception When ShouldCatchException(ex, exceptionCaught)
    Finally
        If exceptionCaught Then
        
            Console.WriteLine("Exception caught!")
            
        End If
    End Try
    
End Sub

Function ShouldCatchException(ex As Exception, ByRef exceptionCaught As Boolean) As Boolean
        
    Console.WriteLine(ex.Message)
    
    exceptionCaught = True
    
    Return False
    
End Function
Apr 16, 2014 at 9:44 AM
@PauloMorgado: yes this looks to me like the equivalent VB code for mads' hack. It's significantly more verbose since it requires a separate function -- but that's also clearer and less hacky.
Apr 17, 2014 at 5:22 PM
Edited Apr 17, 2014 at 6:42 PM
One thing I do not like with the catch(IOException|SQLException ex) syntax is the point that @madst brought up. What is the variable type of the exception? I feel it would be better to maintain the type of the source exception within the catch block. How about listing the supported exception types out like a function argument declaration like this?
catch(ArgumentOutOfRangeException ex1, InvalidCastException ex2) 
{
    if (ex1 != null) Console.WriteLine("It was an ArgumentOutOfRangeException");
    if (ex2 != null) Console.WriteLine("It was an InvalidCastException");
    throw; // throws the exception that is non null ( e.g. throw ex1 ?? ex2;)
}
The compiler will do the simple casting overhead for each variable in the catch condition.

If the exception does not need to be captured into a variable then they can be omitted just like it currently can with a single type.
catch(ArgumentOutOfRangeException, InvalidCastException)
To reduce the number of exception variables that could end up being needed in an exception type filter like this it would be nice to create custom exception groups. Maybe using a variation of the anonymous type syntax like this.
catch(dataException = new {DBConcurrencyException, SyntaxErrorException}) 
{
    // dataException could be an anonymous type derived from System.Exception
    // or a new System.WrappedException type
    throw; // throws the new Exception type
    throw dataException.InnerException; // throws the original exception
}

// conceptual implementation of the WrapperException
public class WrappedException : Exception
{
    public WrappedException(Exception source) :
        base("Wrapped " + source.GetType().FullName, source) {}
}
Putting both of these modifications together would help reduce the number of distinct catch blocks that typically contain redundant rollback logic.
catch(dataError = new {DBConcurrencyException, SyntaxErrorException},
      argumentError = new {InvalidCastException, ArgumentNullException, ArgumentOutOfRangeException}) 
{
    if (dataError != null)
        // handle data errors
    if (argumentError != null)
        // handle argument errors

    // do stuff common for both groups
}
Apr 17, 2014 at 9:49 PM
nickcampau wrote:
One thing I do not like with the catch(IOException|SQLException ex) syntax is the point that @madst brought up. What is the variable type of the exception? I feel it would be better to maintain the type of the source exception within the catch block. How about listing the supported exception types out like a function argument declaration like this?
catch(ArgumentOutOfRangeException ex1, InvalidCastException ex2) 
{
    if (ex1 != null) Console.WriteLine("It was an ArgumentOutOfRangeException");
    if (ex2 != null) Console.WriteLine("It was an InvalidCastException");
    throw; // throws the exception that is non null ( e.g. throw ex1 ?? ex2;)
}
The compiler will do the simple casting overhead for each variable in the catch condition.
That looks like catching two exceptions at the same time. This would be what you mean with standard exception filters:
catch(Exception ex) if (ex is ArgumentOutOfRangeException || ex is InvalidCastException)
{
    if (ex is ArgumentOutOfRangeException) Console.WriteLine("It was an ArgumentOutOfRangeException");
    if (ex is InvalidCastException) Console.WriteLine("It was an InvalidCastException");
    throw; // throws the exception that is non null ( e.g. throw ex1 ?? ex2;)
}
As for the other suggestions, I'm sorry but I personally don't like them at all.
Apr 24, 2014 at 4:30 PM
jods wrote:
@supercat: Would you care to explain how the hack shown by mads would work with VB.NET exception filters?
Static Function CopySecondToFirstAndReturnFalse(Of T)(ByRef First As T, ByVal Second As T)
  First = Second
  Return False
End Function
...
Dim PendingException As Exception = Nothing
Try
  ...
  If PendingException IsNot Nothing Then Throw new VanishedException(PendingException)
Catch Ex As Exception When CopySecondToFirstAndReturnFalse(PendingException, Ex)
  ' Never actually catches
Finally
  Try
      ... Cleanup code that might fail
  Catch Ex As Exception When PendingException IsNot Nothing
      Throw New DoubleFaultException(Ex, PendingException)
  End If
End Try

If an exception is thrown in cleanup following a successful Try the cleanup exception will percolate up normally. If the Try block fails but cleanup succeeds, the try-block exception will percolate up normally. If exceptions occur in both places, a DoubleFaultException will be thrown that wraps both.

Having to use a method for CopySecondToFirstAndReturnFalse is icky--it would be much nicer to have a language compiler provide a syntax to let the Finally block know of any pending exception--but the semantics of the code are basically correct.

The one slight semantic wrinkle relates to the last line of the original Try block. It's possible for an exception thrown within a nested catch block to be seen by an outer-block exception filter, but disappear before execution leaves the nested catch block. If that occurs, code within the Finally block could believe there was a pending when there really wasn't. Since such a scenario should not be considered "normal behavior", it's probably better to throw an exception (which will then genuinely be pending) than stifle the earlier exception or pretend the aforementioned exception is pending when it really isn't.
Apr 24, 2014 at 10:02 PM
Edited Apr 24, 2014 at 10:03 PM
@supercat: thanks for the effort. I know the task can be done given enough code. I was hoping for a short, concise trick similar to mads' trick in C#.

I think we can agree that if you have to write that much code to achieve your goal, a little bit of syntactical sugar would be nice. Doing try {} fault {} (or the equivalent VB) would be way more simple than your code. And more performant at runtime as well.

I am no expert in compiler construction, but given that the feature is already available in the CLR I would think it's not that hard to support.
Apr 30, 2014 at 11:36 PM
I actually find the reverse to be more common in my code - rather than having a block of code that only runs when exception was thrown from try, I want a block of code that runs when exception was not thrown - i.e. try {...} success {...}. It might not seem obvious at the first glance what the difference is between this and just putting the success-block inside try, but the point is to not catch any exceptions in it.

The usual pattern here is when I need to obtain some resource and then work on it, but the obtaining part can fail with an exception. This usually results in code like so:
Foo foo;
try {
   foo = GetFoo();
   foo.PrepareSomehow();
} catch (SomeException) {
   foo = null;
} catch (SomeOtherException) {
   foo = null;
} ...

if (foo != null) {
   foo.Bar();
} else {
   DoSomethingElseEntirely();
}
The annoyances here include having to declare foo separately from assingment, and consequently spelling out its full type, and also having to assign it to some sentinel value on any expected exception and then check for that. It would be nice if there was some syntax that would just let me write this as "try getting foo, if it worked, do the following with it" (without having the "following" part inside the try so that I don't accidentally catch something I don't want).

Now, in Python, this exists in the form of try-else construct, where the else-block of the try (which follows all the except-blocks) runs on success only. In C#, this is a bit trickier because variables are scoped to blocks, and so there needs to be a syntax that allows to bind a variable within the scope of the try (with exceptions being caught), but then use that variable in the else-block. I would propose the following:
try (var foo = GetFoo()) {
   foo.PrepareSomehow();
} catch (Exception ex) if (ex is SomeException || ex is OtherException) {
   DoSomethingElseEntirely();
} else {
   foo.Bar();
}
So try now gets a using-like declaration point where to initialize a variable. The variable is then visible in all blocks of try-catch-finally-else, but it is not considered definitely assigned inside catch & finally (since the initializer could throw) - only inside try & else. The body of the try can be elided completely when there is an initializer, in case no additional exception-guarded preparation is needed:
try (var foo = GetFoo()) 
catch { ... }
else { ... }
For multiple variables, just allow stringing up several try-blocks one after another in a single try-catch-else-finally, kinda like using-statement (except that here it'd actually have to be parsed specially):
try (var foo = GetFoo())
try (var bar = GetBar(foo)) {
   bar.Prepare();
} try (var baz = GetBaz(bar))
catch { ... }
else { ... }
One other option would be to just make all variables inside the body of the try to be visible inside else. So that you can just write:
try {
   var foo = GetFoo();
   foo.PrepareSomehow();
} catch (Exception ex) if (ex is SomeException || ex is OtherException) {
   DoSomethingElseEntirely();
} else {
   foo.Bar();
}
May 1, 2014 at 4:36 PM
Edited May 1, 2014 at 4:37 PM
pminaev wrote:
I actually find the reverse to be more common in my code - rather than having a block of code that only runs when exception was thrown from try, I want a block of code that runs when exception was not thrown - i.e. try {...} success {...}.
A finally (Exception ex) syntax would allow code in the finally block to distinguish whether an exception occurred. In some cases a fault or success block could save an if, but there are enough cases where the success and fail cases should share common code that I think finally (Exception ex) would be desirable even if the other forms existed.

There are some cases where the thing one was really interested in is whether execution made it to the last statement of a block, but in most of those cases I think the real intention would be to have the invariant that if no exception is thrown the last statement of the block must have run; rather than having a means of reporting whether a block has exited via return, it might be as good or better to have a syntax for a try block that would forbid a return within it (one could say try {} finally {code goes here}, but that could have some other effects which may not be desirable.
May 1, 2014 at 4:42 PM
Yes, I like the finally(...) syntax, as well.
May 1, 2014 at 5:33 PM
try-fault is needed feature.
It is not needed for everyday use of course, but very essential for logging.
This way the original exception is not lost.
"throw;" doesn't always do it in the best way.
May 1, 2014 at 6:51 PM
NN wrote:
"throw;" doesn't always do it in the best way.
Can you elaborate a bit more on that?
May 1, 2014 at 7:05 PM
Here the super correct way to rethrow exception without touching the stack trace.
http://rsdn.ru/forum/dotnet/4648691.1
May 1, 2014 at 10:58 PM
NN wrote:
Here the super correct way to rethrow exception without touching the stack trace.
http://rsdn.ru/forum/dotnet/4648691.1
Actually, since .NET 4.5 there is a better way:
catch(Exception ex)
{
    ...
    ExceptionDispatchInfo.Capture(ex).Throw();
}
May 2, 2014 at 3:58 AM
tom103 wrote:
Actually, since .NET 4.5 there is a better way:
catch(Exception ex)
{
    ...
    ExceptionDispatchInfo.Capture(ex).Throw();
}
True, but 'fault' does it automatically for you, so you won';t need to change your code in the future.
May 2, 2014 at 4:02 AM
Also, the catch would cause the exception to be treated as handled for debugging purposes, which is not very convenient when all you want is to rethrow.
May 3, 2014 at 4:28 PM
Here is some feedback from the field: I see lots of exception handling abuse (swallowing or suppression of stack trace). Adding a fault block would give junior developers an easy and obviously correct way to perform compensation logic or logging. Doing it correctly in the current language seems to be too much for many.
May 3, 2014 at 5:12 PM
xor88 wrote:
Adding a fault block would give junior developers an easy and obviously correct way to perform compensation logic or logging.
Not just that, but programmers can hardly be faulted for not doing things correctly in cases where there is no remotely-clean semantically-correct way of doing things. If an exception occurs during "normal execution" cleanup, that exception should not be stifled, but if an exception occurs while unwinding after another exception, the earlier exception should not be overwritten. Stifling the cleanup exception is wrong, but overwriting the other exception is also wrong. Programmers can't exactly be faulted for the fact that they do something wrong there without a means of doing something right. On the other hand, passing a pending exception available to code in a finally-block or a Dispose called from a using block would make it much easier to write semantically-correct code:
void IDisposableEx.Dispose(Exception pendingException)
{
  try
  {
    ... cleanup logic
   }
   catch(Exception ex) when (pendingException != null)
   {
     throw new DoubleException(ex, pendingException);
   }
}
or, for a transaction-scope object:
void IDisposableEx.Dispose(Exception pendingException)
{
  if (!transactionPending) return;
  try
  {
    ... rollback logic
   }
   catch(Exception ex) when (pendingException != null)
   {
     throw new DoubleException(ex, pendingException);
   }
   if (!pendingException)
     throw new AbandonedTransactionException();
}
or, for a reader-writer lock "write" token:
void IDisposableEx.Dispose(Exception pendingException)
{
  if (myLock == null) return;
  if (pendingException == null)
    myLock.Release();
  else
    myLock.Invalidate(pendingException);
  myLock = null;
}
[for the last one, if code acquires a lock for reading and throws an exception, the lock should be released and other code should be allowed to enter it. If an exception occurs with a lock held for writing, and code responding to the exception doesn't act to cleanly release the lock, the lock should be expressly invalidated so that all pending and future efforts to acquire it will throw immediate exceptions. Seldom done, because it's a major pain to do with present syntax, but adding pendingException parameter would make it easy].