Note: this is not a duplicate of Jeff's question.
That question asked "Is an equivalent?" I know there isn't, and I want to know why!
The reason I ask is that I've only just become clear on how important it is, and the conclusion seems very strange to me.
The Exception Handling block of Microsoft's Enterprise Library advises us to use this pattern:
catch (Exception x)
{
if (ExceptionPolicy.HandleException(x, ExceptionPolicies.MyPolicy))
throw;
// recover from x somehow
}
The policy is defined in an XML file, so that means that if a customer has an issue, we can modify the policy to assist with tracking down (or perhaps papering over) the problem to give them a fast resolution until we deal with it properly - which may involve arguing with 3rd parties, about whose fault it all is.
This is basically an acknowledgement of the simple fact that in real applications the number of exception types and their "recoverability" status is practically impossible to manage without a facility like this.
Meanwhile, the CLR team at MS says this is not an option, and it turns out those guys know what they're talking about! The problem is that right before the catch
block runs, any finally
blocks nested inside the try
block will be executed. So those finally
blocks may do any of the following:
- Harmlessly modify the program state (phew, lucky).
- Trash something important in the customer's data, because the program state is screwed up to an unknown degree.
- Disguise or destroy important evidence that we need to diagnose an issue - especially if we're talking about calls into native code.
- Throw another exception, adding to the general confusion and misery.
Note that the using
statement and C++/CLI destructors are built on try
/finally
, so they're affected too.
So clearly the catch
/throw
pattern for filtering exceptions is no good. What is actually needed is a way to filter exceptions, via a policy, without actually catching them and so triggering the execution of finally
blocks, unless we find a policy that tells us the exception is safe to recover from.
The CLR team blogged about this recently:
- Catch, Rethrow and Filters - Why should you care?
- Why catch(Exception)/empty catch is bad
The outcome is that we have to write a helper function in VB.NET to allow us to access this vital capability from C#. The big clue that there is a problem is that there is code in the BCL that does this. Lots of people have blogged about doing it, but they rarely if ever mention the thing about try
/finally
blocks, which is the killer.
What I would like to know is:
- Are there any public statements or direct emails people have received from the C# team on this subject?
- Are there any existing Microsoft Connect suggestions asking for this? I've heard rumours of them but none of the likely keywords turned up anything.
Update: as noted above, I have already searched on Microsoft Connect without finding anything. I have also (unsurprisingly) Googled. I've only found people explaining why they need this feature, or pointing out the advantages of it in VB.NET, or fruitlessly hoping that it will be added in a future version of C#, or working around it, And plenty of misleading advice. But no statement on the rationale for omitting it from all current versions of C#. And the reason I'm asking about existing Connect issues is so that (a) I don't create an unnecessary duplicate and (b) I can tell interested people if I have to create one.
Update 2: Found an interesting old blog post from Eric Gunnerson, formerly of the C# team:
"Yes, being able to put a condition on
a catch is somewhat more convenient
than having to write the test
yourself, but it doesn't really enable
you to do anything new."
That was the same assumption I had until it was properly explained to me!
As to any existing connect bugs. The following issue deals with exception fliters. The user did not explicitly state they wanted them be an actual filter in the sense of when they execute but IMHO it's implied by the logic.
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=401668
Besides that issue though, there are no issues I can find or know of that are related to what you are looking for. I think it would do good to have a separate issue which explicitly calls out the want for VB.Net style exception filters.
I wouldn't worry too much about introducing a duplicate question if you've done a bit of due diligence looking for an existing one. If there is a dupe, Mads will dupe it accordingly and link you to the main request.
As for the part of getting an official response from the C# team, you will likely get that when you either 1) file a connect bug or 2) get duped against the main bug. I really doubt there is an official reason / justification out there right now.
Here's my speculation on the issue: My guess is that this feature simply wasn't on the original C# 1.0 feature set and since that time there hasn't been enough demand to make it into the language. The C# and VB team spend an unbelievable amount of time ranking language features at the start of every ship cycle. We have to make some very difficult cuts at times. Without sufficient demand there is very little chance a feature will make it into the language.
Up until recently I bet you would be hard pressed to find 1 out of 10 people who understood the difference between VB.Net's Try/When and just using a plain old if statement in a C# catch block. It seems to be a bit more on peoples minds lately so maybe it will make it into a future version of the langauge.
Using Exception Filter Inject may be simpler than using the delegate workaround.
For a real answer to your question you will need a response from Anders Hejlsberg, or someone who was in the original design meetings. You might try seeing if you can get it asked by the Channel 9 interviewer next time the C# design team is interviewed.
I'd guess that when the original decision was made, exception filters were seen as an unnecessary complication that might do more harm than good. You can certainly see a desire to remain 'silent' about unproven features in this interview about the decision not to support checked exceptions: The Trouble with Checked Exceptions
.
I think the postmoterm diagnostic scenarios argue strongly for providing access to exception filters in the language. However those scenarios may not have been articulated at the time. Also those scenarios really need proper tooling support, which certainly wasn't available in V1. Finally there may be big negatives about adding this feature that we are not considering.
If there isn't a connect bug on this you should enter one and encourage others to vote it up. [I'd recommend asking for access to the CLR feature rather than attempting to design how it fits in the language.]
I don't believe that Java has a filter option either. Guessing that if it did, we would also see one in C#. VB.net likely has one by chance given that the VB team started with a clean slate.
One thing that might work in your favor as far as gaining this option in a future version of C# is Microsoft's stated goal to maintain parity between laguage features in future versions of C# and VB.net. I would put forward my arguement based on that.
http://www.chriseargle.com/post/2009/01/Parity-Between-Languages.aspx
In regards to the first question, if there was a public statement, then it was more than likely put on the web somewhere, in which case, Google should turn up something (if it exists).
If it is a direct email with the C# team, then it is more than likely that it is under NDA, so it wouldn't be able to be published anyways.
With the second question, there is a search capability on Microsoft Connect which they prompt you to use before entering a new suggestion. If you can't find it, then there probably isn't one.
My recommendation would be to put a suggestion in, and then promote it to get others to weigh in on it.
As I understand them, at the moment of rethrow, the finally handlers in the inner functions are executed and that's what creates problems for you.
But let's say you have an exception filter that passes the exception through without actually rethrowing it. You'll still have to handle it somehow somewhere, and you will run in the same kinds of problems (finally effects) there.
So unless I am misunderstanding something, there is not great gain from having language-supported exception filters.
I can think of at least two reasons why exception filtering is absent from C#
- Allowing exception filters might encourage programmers to do things during first-pass exception handling which would be unsafe at that time, even though they could be done safely within a 'catch' or 'finally'. For example, if code within the "try" block acquires a lock and throws an exception while the lock is held, the lock will be held during the execution of outer exception filters, but will be released before an outer "catch" or "finally" block is run. Also, at least the last time I checked, exceptions that occurred within an exception filter and not caught within it were silently stifled--something of an ugly situation.
- The implementers of C# have a vision of making their language 'framework agnostic'. If C# supported .net first-pass exception filtering, programs which used that feature might be unusable on frameworks which handle exceptions differently. This is the same reason that C# forbids programs from overriding `Object.Finalize()`. While the reasoning surrounding `Object.Finalize()` is flawed (correct use of destructors requires use of other platform-specific methods, so requiring the use of destructor syntax for `Object.Finalize()` accomplishes nothing except t77o encourage the writing of defective software) the reasoning does make some sense with regard to exception filters. On the other hand, the proper way to deal with that issue would be to expose some exception-filter-related features even if one didn't expose exception filters directly.
One feature I'd really like to see in C# and vb, which would require the use of exception filters to implement but which would not require exposing them directly, would be an optional Exception
parameter for a finally
block. This parameter would be null
if no uncaught exception occurs; otherwise it would hold the exception in question. This would allow for situations where a program will want to do something when an exception occurs, but not actually "handle" it. In most cases, the Exception
parameter wouldn't be used for anything except to check for null
(meaning the feature would be equivalent to exposing fault
blocks), but it would offer advantages in cases where an exception occurs during cleanup. Presently, if an exception occurs during a finally
block, it's necessary to either stifle the finally
-block exception or overwrite the pre-existing one. Having the earlier exception available to the finally
block code would enable it to either wrap or log it.