

C# 6 exception filters and how they are more than syntactic sugar - bursurk
http://volatileread.com/Wiki/Index?id=1087

======
Locke1689
Short story about exception filters: they're mostly there for crash dumps.

The background is that there is a piece of functionality in Windows previously
called Watson, now called Windows Error Reporting. It's that dialog that pops
up when an application crashes that asks if you'd like to report the crash to
Microsoft. If you do, it sends a crash dump to Microsoft, where it can then be
routed to the owner of the application, even if the application isn't actually
developed by Microsoft.

So a lot of developers in the know have designed their applications so that
unrecoverable errors actually purposely cause the application to crash so that
they can get a dump from WER. One of the standard ways of doing this is simply
wrapping your code in a catch at the top level and then calling
Environment.FailFast to crash the process.

The problem is that sometimes the stack is destroyed in this process. Note
that I didn't say the stack trace -- the _stack_ is destroyed. You can see
this if you catch and rethrow an exception. The locals from the original
exception are gone, so now the dump is far more difficult to debug.

Exception filters let you get around this because they don't actually pop
anything, including the exception, from the stack, so if you FailFast, you
crash with the full stack of the process.

A number of .NET developers had previously figured this out and were doing a
bunch of nasty stuff to get this behavior, like including a VB net module with
an exception filter fail-fast, or ildasm/ilasming their assembly. We tried a
bunch of these methods on the compiler and they were all a source of many
really obnoxious bugs, so eventually another compiler developer and I just
said "screw it" and implemented exception filters in C#. All the bugs went
away and we lived happily ever after.

Oh, and now exception filters are in the language.

~~~
anon4
Honest question, I'm not familiar with C#: would putting the Log in the
finally clause not have the same behaviour? That is,

    
    
      bool _operation_X_success = false;
      try {
          ...
          _operation_X_success = true;
      } finally [
          if (!_operation_X_success) {
              Log("blah blah");
          }
      }

~~~
SideburnsOfDoom
The finally clause does not have access to the exception details, as it
executes regardless of whether there is an exception or not. You can't do
"Log(ex);" in the finally block. And you would want to put the exception into
the log.

You also need a boolean and a few extra lines of control code as your example
shows.

------
Pxtl
So basically, the CLR has ugly behavior on rethrows that can only be sanely
described as a bug but it's a common-law feature at this point so we're using
an ugly linguistic construct to work around it.

~~~
Lx1oG-AWb6h_ZG0
I'm confused, what is the alternative here? I expect the IDE to stop when an
exception is not handled. Should it stop even if it is?

~~~
Someone
Separate exception catching from stack unwinding as in the Lisp condition
system, where low-level code decides when to call high-level code and what
options to present it, and the high-level code does whatever it wants to do
and then picks an option.

That more or less gives you what Microsoft calls 'edit and continue' in every
program, where your high-level code decides what code does the edit and
decides on how to continue.

Some discussion with real-world usage scenarios at [http://lambda-the-
ultimate.org/node/1544](http://lambda-the-ultimate.org/node/1544). Example at
[http://c2.com/cgi/wiki?LispRestartExample](http://c2.com/cgi/wiki?LispRestartExample)

------
junto
Horrible looking magic strings there. Isn't it better to just throw typed
exceptions? Then you can catch(MyCustomException).

~~~
zaroth
Often the only difference between encoding the type in a string, and encoding
the type in a full-blown typed Exception is perhaps 'Find All References'.
Typing the Exception can be a waste of typing and unnecessary cruft. More
"structure" is not always better.

If there's some unique data which must be carried back up the stack with the
Exception it's a different story.

------
kazinator
Exception filters seem to be imitated from Win32 structured exception handling
(SEH).

See "Example 3" here:

[https://msdn.microsoft.com/en-
us/library/windows/desktop/ms6...](https://msdn.microsoft.com/en-
us/library/windows/desktop/ms681409%28v=vs.85%29.aspx)

in particular, how FilterFunction is used.

------
chadzawistowski
In Python, you can simply type `raise` to re-raise the exception you caught,
preserving the stack trace.

~~~
ufmace
In C#, throw also re-throws and preserves the stack trace in the exception
object. What the article points out that it doesn't do is preserve the full
call stack and method state in the Visual Studio debugger, and that only if
you explicitly turn off break on throw, leaving it in break on throwing
uncaught exceptions instead.

In fact, changing state in an exception filter method that always returns
false sounds terrible to me. What if you actually need to do something with
that exception, or to clean up state? What if the Log method does something
wrong that you need to debug? Exception filters are handy, but I hope to never
see them used like that.

Now the new null propagation operator, on the other hand, get me some of that,
and I hope to see it used everywhere.

------
RomanPushkin
catch if(Log())

Doesn't look great. It's not easy to understand what this code does. I'd
better rewrite it this way:

catch if(IsExceptionLogged())

So we can see here "Is" keyword, it gives us a hint that this function returns
boolean. We can see the main operation, and it's more human-readable. And we
can easily understand what do we mean here. Because in case of Log() we have
to think - should we catch if it was logged or if it was not logged.

Maybe it is useful in some cases. But unfortunately the code quality doesn't
depend on the tools one uses, and it's nothing about language features. 99% of
developers don't know how to use C# 1.0. There are so still a lot for them to
learn.

Maybe even

catch if(IsExceptionHandled())

is better. Because I don't see any reasons why should we catch exceptions if
it was logged. Yep, it was logged - is it a good decision factor to catch?
Logging often can be disabled in configuration.

~~~
DougBTX
Calling the Log function there is a hack to work around the stack being
unwound inside catch blocks, it isn't being used to control whether the catch
block is run based on whether logging is turned on or not, so those suggested
alternative names seem confusing.

"IsExceptionLogged" implies that the function is being called for its return
value, to work out whether the exception is being looked or not, but in this
usecase the Log function is being called for its side affects, and the return
value is a boolean simply to appease the type checker.

