Value assignment try-catch

Topics: C# Language Design
Dec 31, 2014 at 9:32 AM
As a shortcut of value assignment construct with try-catch block:
int a;
try
{
    a = GetValue();
}
catch
{
    a = 1000;
}
I would like to propose an "inline" syntax:
int a = try GetValue() catch 1000;
Or similar to conditional operator:
int a = try GetValue() : 1000;
To keep the syntax simple I would not add any exception filtering for the catch – most of the time this construct contains default value in a general catch block.
Dec 31, 2014 at 1:34 PM
Swallowing exceptions like in your initial example is not exactly the norm, you should try to come up with a more realistic example (if such an example even exists).
Dec 31, 2014 at 3:03 PM
Thanks for your reply.
Please consider the following situation:
int winOpacity;
try
{
    winOpacity = (int)Microsoft.Win32.Registry.GetValue( _regKey, "Opacity", null );
}
catch
{
    winOpacity = 100;
}
I would not like to care about the following cases
  • if the key or value exists or not
  • the type of the value (if it is string or dword or any other type)
  • if the value is string then which format it has (integer or double; if double, which culture it was set on)
Of course, the value is consistent in my own application, but all of these cases can occur if the registry value is set by some other 3rd party applications.

Also, checking of all these cases can be implemented, but handling of them is just not important semantically (I don't want to waste code lines for it).

BTW, if you don't think my suggestion is a good idea, I am not stuck to it. :)
Dec 31, 2014 at 3:32 PM
That's a very dangerous practice.

And it looks like you like exception driven logic.

This code has less chances to throw exceptions than yours:
int winOpacity;
try
{
    winOpacity = (int)Microsoft.Win32.Registry.GetValue(_regKey, "Opacity", 100);
}
catch
{
    winOpacity = 100;
}
If you really want this (I don't), you can always write a library to do that:
public static T Eval<T>(Func<T> eval, T defaultValue)
{
    try
    {
        return eval();
    }
    catch
    {
        return defaultValue;
    }
}
If you feel like it, you can even create one version that accepts a list of acceptable (or not acceptable) exceptions.
Jan 1, 2015 at 5:53 PM
PauloMorgado wrote:
That's a very dangerous practice.
People who design exception-handling features in languages often figure that because exceptions should only be handled by code that knows what should be done in response, that there's no reasonable way for code to handle any exception which was not specifically anticipated. Such thinking ignores the fact that in many cases the proper handling of an exception will have almost nothing to do with the nominal cause of the exception, and everything to do with the state of the system. If, as is common, the system will be in essentially the same valid state when a method exits with an exception as it was just before the method was called, and if (as is also common) the system would be prepared to proceed without having achieved the aims of the method in question, then the proper way of handling the exception will be to proceed in such fashion, regardless of what caused the original exception. The dangers of the indicated approach stem from the inability of languages and frameworks to distinguish between exceptions that be properly handled by acknowledging the inability to perform a requested action, and those which indicate problems beyond that.

One of the fundamental problems with the exception-handling paradigm in C++ which follows through in Java and .NET is that there is no mechanism for distinguishing between exceptions that get thrown from outer methods for "expected" reasons, versus those which occur because an inner method threw an unexpected exception. The concept of checked exceptions would be very useful if checked-ness was a property of catch/throw sites and exception instances, rather than a property of exception types.

I wish there were a mechanism by which methods could be declared as throwing exceptions could have a calling convention which returned an Exception and a Func<Exception,Exception> as secondary return values; calling code would be required to check whether the first Exception was null and, if not, handle the fact that an exception was thrown. If the caller was expecting the exception, it would dispatch to the handling code directly without having to use the system's exception-throwing mechanism. If it wasn't expecting the exception, it would pass the exception to the supplied function if non-null and throw the result. If such an approach existed, with distinct syntax for catching expected and potentially-unexpected exceptions, that would allow expected exceptions to be handled much more efficiently than unexpected ones, while ensuring that code explicitly acknowledged the existence of error conditions. Further, if such an approach existed, syntax such as described by the OP would be both safe and useful. Unfortunately, I don't see any plausible way such a thing will ever be added to .NET or any of its languages.
Jan 1, 2015 at 7:08 PM
Are you talking about HRESULTs?

Exceptions should be used for exception situations. You should be prepared for them but not as if they were normal.

Of course, no one does that all the times. Not even the BCL.
Jan 3, 2015 at 8:08 AM
kolozsaron wrote:
Thanks for your reply.
Please consider the following situation: ... I would not like to care about the following cases...
You also don't care about SecurityException and IOException that can be thrown by GetValue. Granted, those are really exceptional situations that may very well never arise in practice.

Anyway, the main issue with this approach is that the user will never know why the feature doesn't work. From time to time I run into such cases, an app doesn't do what is supposed to do and there's no information whatsoever about what went wrong, not even a crash. It's not about me thinking that this is good or wrong but I can tell you that you'll have a very hard time trying to sell such a language feature to the language design team.

supercat wrote:
If, as is common, the system will be in essentially the same valid state when a method exits with an exception as it was just before the method was called, and if (as is also common) the system would be prepared to proceed without having achieved the aims of the method in question, then the proper way of handling the exception will be to proceed in such fashion, regardless of what caused the original exception. The dangers of the indicated approach stem from the inability of languages and frameworks to distinguish between exceptions that be properly handled by acknowledging the inability to perform a requested action, and those which indicate problems beyond that.
That's a bunch of sugar coated nonsense. What system are you talking about? The operating system? The OP's application? The third party application? And which is the valid state and who decides what is valid? In OP's example the main danger is not about continuing after the exception but about not surfacing the error anywhere.
One of the fundamental problems with the exception-handling paradigm in C++ which follows through in Java and .NET is that there is no mechanism for distinguishing between exceptions that get thrown from outer methods for "expected" reasons, versus those which occur because an inner method threw an unexpected exception.
Yeah, too bad that C++/Java/.NET don't have some kind of A.I. system built in to know when your method is expecting and exception.
I wish there were a mechanism by which methods could be declared as throwing exceptions could have a calling convention which returned an Exception and a Func<Exception,Exception> as secondary return values;
This, as usual, has nothing to do with the OP's suggestion. Nor does this solve any actual problem, you only think it does because you use certain words without attempting to assign a definite meaning to them.

I think it's quite unfortunate that you repeatedly hijack other people's threads in attempt to express your views. And the fact that you write page long posts where many things are left (intentionally?) vague doesn't help.
Jan 3, 2015 at 6:30 PM
mdanes wrote:
That's a bunch of sugar coated nonsense. What system are you talking about? The operating system? The OP's application? The third party application? And which is the valid state and who decides what is valid? In OP's example the main danger is not about continuing after the exception but about not surfacing the error anywhere.
If a user selects "File:Open" and selects a file to open, and the program tries to create a new SuperWidget object using data from a file stored on disk, there may be countless ways the operation can fail; in 99% of cases the proper action will be to inform the user that the file couldn't be opened. If the attempt to open the file corrupts a data structure which is shared with other open documents, it may be better to kill the entire application rather than allow the user to keep working with other now-corrupted documents, but in most cases having the entire application die because of a not-specifically-anticipated problem loading the file would be rather obnoxious.
One of the fundamental problems with the exception-handling paradigm in C++ which follows through in Java and .NET is that there is no mechanism for distinguishing between exceptions that get thrown from outer methods for "expected" reasons, versus those which occur because an inner method threw an unexpected exception.
Yeah, too bad that C++/Java/.NET don't have some kind of A.I. system built in to know when your method is expecting and exception.
It wouldn't be an AI system. Basically it would be something similar to Java's "throws" directive on the called-method side, and a requirement that program which calls a method with a throws directive must either catch the exception, propagates it, or consider it unexpected. Additionally, finally block should be informed of whether the try block threw an exception; the normal locking pattern should have locks which are acquired for reading be released when a guarded block exits via exception, but have blocks which are acquired for writing be invalidated in that case such that any pending or future acquisition attempts will immediately fail. If in the course of stack unwinding all invalidated objects get abandoned, the fact that the objects were corrupted shouldn't interfere with continued program execution. If something which is vital to continued operation gets corrupted, having it be expressly invalidated will ensure the program dies off quickly (as it should).
I think it's quite unfortunate that you repeatedly hijack other people's threads in attempt to express your views. And the fact that you write page long posts where many things are left (intentionally?) vague doesn't help.
My intention was to indicate that I would consider the OP's idea to be a good one in a language/framework where various other conditions applied. It is not a good fit for .NET languages where those conditions do not apply, but I did not want the original author to think it was a totally-bad idea.
Jan 4, 2015 at 4:42 PM
supercat wrote:
If a user selects "File:Open" and selects a file to open, ...
That's common sense, everyone who has some familiarity with error handling knows all that. You've probably tried to say the same thing in the corresponding paragraph from your previous post but that paragraph looks more like a critique of exception handling systems for a perceived (not actual) flaw. Of course you can't distinguish between exceptions that can properly be handled "and those which indicate problems beyond that" because it all depends on the application code.
It wouldn't be an AI system.
But that's exactly how it sounds in your description.
Basically it would be something similar to Java's "throws" directive on the called-method side, and a requirement that program which calls a method with a throws directive must either catch the exception, propagates it, or consider it unexpected.
So you're basically saying that the programmer is supposed to declare what's expected and what's unexpected? And if the programmer gets it wrong? The expected becomes unexpected and vice versa, what problem did we solve? Proper error handling is hard and you won't make it easier with patchwork. The only thing that you can do to simplify error handling is to use transactions everywhere but that's not trivial to implement and in many cases it's absolute overkill.
Additionally, finally block should be informed of whether the try block threw an exception; the normal locking pattern should have locks which are acquired for reading be released when a guarded block exits via exception, but have blocks which are acquired for writing be invalidated in that case such that any pending or future acquisition attempts will immediately fail. If in the course of stack unwinding all invalidated objects get abandoned, the fact that the objects were corrupted shouldn't interfere with continued program execution. If something which is vital to continued operation gets corrupted, having it be expressly invalidated will ensure the program dies off quickly (as it should).
OK, let's make this even more complicated by dragging threading into the matter. And let's make it confusing too by saying "normal locking pattern" in a C# forum which will probably leave some people scratching their heads: since when C#'s lock is a reader-writer lock?
My intention was to indicate that I would consider the OP's idea to be a good one in a language/framework where various other conditions applied. It is not a good fit for .NET languages where those conditions do not apply, but I did not want the original author to think it was a totally-bad idea.
But this the "C# language design" forum, not the "Imaginary language forum I whish to invent" forum. All suggestions are likely to be judged in the context of C#/.NET and it's very much irrelevant if they're good/bad in some other language like, say, Haskell.
Jan 4, 2015 at 5:19 PM
supercat wrote:
Basically it would be something similar to Java's "throws" directive on the called-method side, and a requirement that program which calls a method with a throws directive must either catch the exception, propagates it, or consider it unexpected.
I do like the theory behind the throws clause in Java. However, I find that in practice it's much more of a nuisance than anything else.

It's hard for me to tease apart the language concept from the paradigmic differences between the two languages, though. In my experience Java developers are much more nonchalant about exception handling, despite this construct. For example, the preference seems to be to not bother validating arguments up-front in a method body, rather let the code eventually throw whatever exception will likely result from an invalid value.

With checked exceptions the same situation arises. Sure, when calling JRE methods that already declare checked exceptions you're forced to do something by the compiler, and that "do something" usually results in either propagating that checked exception raw or catching and eating it. The latter is obnoxiously common when within a method implementing/overriding another method that does not declare any checked exceptions since they are a part of the method signature. As for non-checked exceptions, more often than not it seems that people treat them as not existing.

For example, I've recently done work with a common asynchronous programming library that allows registration of continuations with a simple functional interface whose method declares no checked exceptions. If the continuation throws an unchecked exception, e.g. NullPointerException, the subsequent promise simply never completes. The exception bubbles up the stack trace of whatever thread happened to trigger the continuation which should have no expectation of having to handle said exceptions anyway.

So, like most things in Java, checked exceptions, in my opinion, is another good idea with a horrible implementation, serving little more than to make life harder on the developer without providing any real benefit. As with secure programming, defensive programming is a discipline that must be taught.

I've not heard the story of writing Roslyn analyzers which also take XML documentation into account. I would think that since XML documentation includes an <exception> element that you could probably write analyzers which would emit diagnostics in a manner similar to checked exceptions.
Jan 6, 2015 at 9:06 AM
Halo_Four wrote:
With checked exceptions the same situation arises. Sure, when calling JRE methods that already declare checked exceptions you're forced to do something by the compiler, and that "do something" usually results in either propagating that checked exception raw or catching and eating it. The latter is obnoxiously common when within a method implementing/overriding another method that does not declare any checked exceptions since they are a part of the method signature. As for non-checked exceptions, more often than not it seems that people treat them as not existing.
This shouldn't be too surprising, nobody likes to write error handling code. If a language feature attempts to enforce some sort of error handling then there's a good chance that people will engage in active avoidance of the feature either by simply ignoring it if it's optional or by doing the least amount of work that keeps the compiler (and not the application code) happy.

However, Java's checked exceptions yielded something positive, by design or maybe by accident, the exception hierarchy is better compared to .NET. In .NET exceptions that usually have external causes (IOException for example) have the same base class (SystemException) as exceptions that are normally associated with programming errors (NullReferenceException for example). And you know that something's messed up when you see framework code which does "catch (Exception ex)" and then attempts to figure out if it should rethrow or eat the exception by doing something like "if (ex is NullReferenceException || ex is StackOverflowException....".
Jan 6, 2015 at 9:06 PM
mdanes wrote:
Halo_Four wrote:
With checked exceptions the same situation arises. Sure, when calling JRE methods that already declare checked exceptions you're forced to do something by the compiler, and that "do something" usually results in either propagating that checked exception raw or catching and eating it. The latter is obnoxiously common when within a method implementing/overriding another method that does not declare any checked exceptions since they are a part of the method signature. As for non-checked exceptions, more often than not it seems that people treat them as not existing.
This shouldn't be too surprising, nobody likes to write error handling code. If a language feature attempts to enforce some sort of error handling then there's a good chance that people will engage in active avoidance of the feature either by simply ignoring it if it's optional or by doing the least amount of work that keeps the compiler (and not the application code) happy.

However, Java's checked exceptions yielded something positive, by design or maybe by accident, the exception hierarchy is better compared to .NET. In .NET exceptions that usually have external causes (IOException for example) have the same base class (SystemException) as exceptions that are normally associated with programming errors (NullReferenceException for example). And you know that something's messed up when you see framework code which does "catch (Exception ex)" and then attempts to figure out if it should rethrow or eat the exception by doing something like "if (ex is NullReferenceException || ex is StackOverflowException....".
Maybe. RuntimeException is the base class of a huge number of possible exceptions, many of which aren't directly programmer error. The hierarchy also doesn't eliminate such code, which is why Java did add catching multiple exception types in the same catch clause. .NET always had a more elegant solution to this issue via exception filters, C# just didn't allow using them directly until Roslyn.

While I agree that developers tend to avoid tedious code like argument validation it is absolutely critical not only to ensure the sanity of your code but especially if anyone else might call that code. In my opinion neither C# nor Java go far enough in making it easy to write this code. In C#'s case at least there are decent exceptions for representing the different reasons that an argument might be invalid and those exceptions accept the name of the argument to be included in a properly localized message. Java has barely any of this.
Jan 7, 2015 at 7:09 AM
Halo_Four wrote:
Maybe. RuntimeException is the base class of a huge number of possible exceptions, many of which aren't directly programmer error. The hierarchy also doesn't eliminate such code, which is why Java did add catching multiple exception types in the same catch clause. .NET always had a more elegant solution to this issue via exception filters, C# just didn't allow using them directly until Roslyn.
It's been a while since I touched any Java stuff. I took a quick look at the documentation and the list of "direct known subclasses" is reasonable for the most part, one could say that they at least tried. But it's difficult to get this right because it's not always clear which exceptions are the result of a programming error and which are not. OP's example shows this, most of us would consider InvalidCastException/NullReferenceException to be the result of programming errors but, best practices aside, that's not the case in this example.

BTW, both exceptions can be avoided by using code like:
int winOpacity = (GetValue( _regKey, "Opacity", null ) as int?) ?? 100;
I still don't like this in the general case because it leads to the silent failure of the feature but it's quite possible that this is a reasonable thing to do in this particular case.
While I agree that developers tend to avoid tedious code like argument validation it is absolutely critical not only to ensure the sanity of your code but especially if anyone else might call that code.
Well, I was specifically talking about handling exceptions but I suppose argument validation is related. Not necessarily because it relies on exceptions but because doing upfront validation minimizes the chance that program state is corrupted.
In my opinion neither C# nor Java go far enough in making it easy to write this code. In C#'s case at least there are decent exceptions for representing the different reasons that an argument might be invalid and those exceptions accept the name of the argument to be included in a properly localized message. Java has barely any of this.
Heh, while I was looking at Java documentation I found this gem in the documentation of the DOMException class:

"Implementations should raise other exceptions under other circumstances. For example, implementations should raise an implementation-dependent exception if a null argument is passed when null was not expected."

Priceless :)
Jan 8, 2015 at 5:34 AM
Edited Jan 8, 2015 at 5:56 AM
I still want to propose more general feature: http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/6504697-block-code-as-value-another-syntax-for-semicolon

Would be
int a = try { return GetValue(); } catch { return 1000; };
P.S. Probably new short keyword instead of "return" should be used for such usages, "lret" (local return) for example.
Jan 8, 2015 at 6:35 AM
agat50 wrote:
I still want to propose more general feature: http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/6504697-block-code-as-value-another-syntax-for-semicolon ...
I'm not sure that you realize what you're proposing, your "block code as value" is really "allow (certain) statements to be treated as expressions". That is, statements such as lock, using and try need to work as expressions when used inside an expression. That's a significant language change and it's not clear what the benefit is.

Out of 4 examples you have provided only the 3rd is interesting because it enables the use of anonymous types in more situations. The 1st example looks more like an abuse of the proposed feature. The 2nd example is useless, you can simply write a = dataInstance.Member1 inside the lock. The 4th example just enables the use of type inference, that's nice but not useful enough to justify the feature.

And the idea of "redundant method" will probably raise some eyebrows. I've rarely seen redundant methods in practice, most of the time I have to deal with large methods that do everything and some more and they need to be split into smaller, more focused methods.
Jan 8, 2015 at 7:17 AM
Edited Jan 8, 2015 at 7:29 AM
mdanes wrote:
agat50 wrote:
I still want to propose more general feature: http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/6504697-block-code-as-value-another-syntax-for-semicolon ...
I'm not sure that you realize what you're proposing, your "block code as value" is really "allow (certain) statements to be treated as expressions". That is, statements such as lock, using and try need to work as expressions when used inside an expression. That's a significant language change and it's not clear what the benefit is.
First of all, thanks for response.

Yes, unfortunately i read about "Everything Is an Expression" after proposal was submitted already, it would let me specify proposal in common used words. About significant changes... All this feature is just sugar for
static T1 Eval<T1>(Func<T1> func1)
{
    return func1();
}

if(Eval(() => {
    /*Expression body*/
}))
{

}
With new "return" keyword it would be easy to locate such statements imho, with old a little harder. What is more important - it won't break backward compatibility (probably except
static int Mthd1()
{
    {
        return 0;
    }
}
cases, which are quite rare).
Out of 4 examples you have provided only the 3rd is interesting because it enables the use of anonymous types in more situations. The 1st example looks more like an abuse of the proposed feature. The 2nd example is useless, you can simply write a = dataInstance.Member1 inside the lock. The 4th example just enables the use of type inference, that's nice but not useful enough to justify the feature.
1st example about important advantage - it allows have more structured code and minimal scope for vars. I find it very useful. 2nd and 4th is the same, i agree. 4th - long type definitions instead of var is quite annoying actually, plus it allows multiple returns from using easy. 'var's are better for refactoring, easy reading.
static void Mthd1()
{
    var t = using(var resource = GetResource())
    {
        return Tuple.Create(resource.Foo(),resource.Bar());
    };
    var a = t.Item1;
    var b = t.Item2;
}
And the idea of "redundant method" will probably raise some eyebrows. I've rarely seen redundant methods in practice, most of the time I have to deal with large methods that do everything and some more and they need to be split into smaller, more focused methods.
There would be many of "redundant methods" without lambdas, for example. My proposal is just slight improvement.
Jan 8, 2015 at 9:10 AM
agat50 wrote:
About significant changes... All this feature is just sugar for ...
I don't see the connection between "significant changes" and implementation details. The compiler can't magically perform the transformation you propose. The parser needs to be modified, new syntax node types have to be created etc. And the suggested implementation is quite naïve, there's absolutely no need to use lambda expressions, they lead to unnecessary allocations for delegates and closures.
1st example about important advantage - it allows have more structured code and minimal scope for vars. I find it very useful.
It also make the code harder to read. Instead of seeing a clear "if (x * y > 0)" you see a bunch of lines and you need to scan through all of them to figure out what the condition is. This also makes it easier to introduce side-effects in places that are typically side-effect free. I like keeping the variable scope as small as possible but not at any cost.
4th - long type definitions instead of var is quite annoying actually, plus it allows multiple returns from using easy. 'var's are better for refactoring, easy reading.
There are many people who would say that there's nothing "easy reading" in your latest example. Some people like to use 'var' other the places while others do not. If there's some common ground then that is to use 'var' when the type is obvious and that's not the case in your example.
There would be many of "redundant methods" without lambdas, for example. My proposal is just slight improvement.
Yes, but lambdas are far more helpful, attempting to implement closures by yourself would be quite ugly. Your proposal attempts to turn the language inside-out for the debatable benefit of using type inference in more places. That's going to be a tough sell.
Jan 12, 2015 at 5:47 PM
mdanes wrote:
So you're basically saying that the programmer is supposed to declare what's expected and what's unexpected? And if the programmer gets it wrong? The expected becomes unexpected and vice versa, what problem did we solve? Proper error handling is hard and you won't make it easier with patchwork. The only thing that you can do to simplify error handling is to use transactions everywhere but that's not trivial to implement and in many cases it's absolute overkill.
Sometimes it is useful to have a method throw particular exceptions to indicate certain things. For example, an Add method might throw InvalidOperationException when attempting to add an item that already exists. Code which seeks to catch that exception will likely assume that it was thrown for that reason. If the Add method calls the passed-in object's GetHashCode method which is broken and throws InvalidOperationException for some totally-unrelated reason, code which is expecting to handle the situation where the passed-in item is already in the collection should not try to handle the InvalidOperationException percolating through the Add method.

Perhaps "expected" and "unexpected" aren't the best words; the idea is to distinguish between exceptions which have a specific meaning defined by a method's contract, and exceptions whose meaning is less-well defined.
Additionally, finally block should be informed of whether the try block threw an exception; the normal locking pattern should have locks which are acquired for reading be released when a guarded block exits via exception, but have blocks which are acquired for writing be invalidated in that case such that any pending or future acquisition attempts will immediately fail. If in the course of stack unwinding all invalidated objects get abandoned, the fact that the objects were corrupted shouldn't interfere with continued program execution. If something which is vital to continued operation gets corrupted, having it be expressly invalidated will ensure the program dies off quickly (as it should).
OK, let's make this even more complicated by dragging threading into the matter. And let's make it confusing too by saying "normal locking pattern" in a C# forum which will probably leave some people scratching their heads: since when C#'s lock is a reader-writer lock?
I was rambling a bit there. The point I wanted to make is that having code catch and swallow most exceptions without regard for what they are would be a reasonable idea if a mechanism existed to ensure that problems that weren't benign would get noticed.
My intention was to indicate that I would consider the OP's idea to be a good one in a language/framework where various other conditions applied. It is not a good fit for .NET languages where those conditions do not apply, but I did not want the original author to think it was a totally-bad idea.
But this the "C# language design" forum, not the "Imaginary language forum I whish to invent" forum. All suggestions are likely to be judged in the context of C#/.NET and it's very much irrelevant if they're good/bad in some other language like, say, Haskell.
I wanted to soften what I perceived as "only a maniac would use such a feature" by suggesting that while there are contexts where such a feature would be useful and safe, .NET is not at present one of them. I drifted a bit into "rambling mode" so my original point got lost, but the intention was to be friendly.
Jan 12, 2015 at 6:15 PM
Halo_Four wrote:
supercat wrote:
Basically it would be something similar to Java's "throws" directive on the called-method side, and a requirement that program which calls a method with a throws directive must either catch the exception, propagates it, or consider it unexpected.
I do like the theory behind the throws clause in Java. However, I find that in practice it's much more of a nuisance than anything else.
I think the main problem is that it assumes that if some callers of a method will expect to directly handle some particular failure conditions, all callers will either expect to do so, or be invoked in contexts where the exception would have the same meaning to their callers as it would to them. Checked exceptions are great in cases where the above assumption holds, but many methods may be invoked both in contexts that expect to deal with failures and in contexts that do not.
It's hard for me to tease apart the language concept from the paradigmic differences between the two languages, though. In my experience Java developers are much more nonchalant about exception handling, despite this construct. For example, the preference seems to be to not bother validating arguments up-front in a method body, rather let the code eventually throw whatever exception will likely result from an invalid value.
I think there's something to be said for a philosophy that arguments should be validated at the point where code receiving them would be able to do something more useful (or less harmful) than code to which it would give them.
With checked exceptions the same situation arises. Sure, when calling JRE methods that already declare checked exceptions you're forced to do something by the compiler, and that "do something" usually results in either propagating that checked exception raw or catching and eating it. The latter is obnoxiously common when within a method implementing/overriding another method that does not declare any checked exceptions since they are a part of the method signature. As for non-checked exceptions, more often than not it seems that people treat them as not existing.
The right approach in many cases should be to have the checked exception propagate in a form which would indicate that it it has propagated through a layer where it was unexpected. Unfortunately, that approach is the one which requires the most verbosity on the part of the method caller. Ironic, since the scenario where that approach would be the right one is probably much more common than the scenario which is catered to by having a caller declare its own "throws" clause.
Jan 12, 2015 at 7:52 PM
supercat wrote:
Sometimes it is useful to have a method throw particular exceptions to indicate certain things. For example, an Add method might throw InvalidOperationException when attempting to add an item that already exists. Code which seeks to catch that exception will likely assume that it was thrown for that reason. If the Add method calls the passed-in object's GetHashCode method which is broken and throws InvalidOperationException for some totally-unrelated reason, code which is expecting to handle the situation where the passed-in item is already in the collection should not try to handle the InvalidOperationException percolating through the Add method.

Perhaps "expected" and "unexpected" aren't the best words; the idea is to distinguish between exceptions which have a specific meaning defined by a method's contract, and exceptions whose meaning is less-well defined.
OK, let's say we do not use expected/unexpected but buggy/non-buggy. Let's also say that exceptions thrown by using throw are non-buggy by default (otherwise you need a different mechanism to throw non-buggy exception and that mechanism may very well be misused). If GetHashCode throws an InvalidOperationException the runtime must mark the exception object as buggy when the search for an exception handler exits GetHashCode because GetHashCode has not been marked as throwing InvalidOperationException (via something like "throws InvalidOperationException"). So far this seems to work quite well.

But... there's nothing stopping the Add method from calling another method which too throws a non-buggy InvalidOperationException. Now, how do you distinguish that one from the exception thrown by Add itself? Add another mechanism which allows the code to manually transform non-buggy exceptions in buggy exceptions? Maybe, but by adding more stuff you increase the chance that people will misuse it and we're back at square one.

And OP's example is more problematic than this, he wants to catch and swallow InvalidCastException and NullReferenceException. Unlike exceptions thrown by using throw those should start life as buggy. For syntax like the proposed one to be safe there should exist a kind of casts that generates non-buggy exceptions. Something like
int winOpacity = try trycast<int>(Microsoft.Win32.Registry.GetValue(_regKey, "Opacity", null)) catch 100;
Additional complication and another way for people to get things wrong.
Jan 13, 2015 at 6:36 PM
mdanes wrote:
supercat wrote:
Sometimes it is useful to have a method throw particular exceptions to indicate certain things. For example, an Add method might throw InvalidOperationException when attempting to add an item that already exists. Code which seeks to catch that exception will likely assume that it was thrown for that reason. If the Add method calls the passed-in object's GetHashCode method which is broken and throws InvalidOperationException for some totally-unrelated reason, code which is expecting to handle the situation where the passed-in item is already in the collection should not try to handle the InvalidOperationException percolating through the Add method.

Perhaps "expected" and "unexpected" aren't the best words; the idea is to distinguish between exceptions which have a specific meaning defined by a method's contract, and exceptions whose meaning is less-well defined.
OK, let's say we do not use expected/unexpected but buggy/non-buggy. Let's also say that exceptions thrown by using throw are non-buggy by default (otherwise you need a different mechanism to throw non-buggy exception and that mechanism may very well be misused). If GetHashCode throws an InvalidOperationException the runtime must mark the exception object as buggy when the search for an exception handler exits GetHashCode because GetHashCode has not been marked as throwing InvalidOperationException (via something like "throws InvalidOperationException"). So far this seems to work quite well.

But... there's nothing stopping the Add method from calling another method which too throws a non-buggy InvalidOperationException. Now, how do you distinguish that one from the exception thrown by Add itself? Add another mechanism which allows the code to manually transform non-buggy exceptions in buggy exceptions? Maybe, but by adding more stuff you increase the chance that people will misuse it and we're back at square one.
How about "contractual/non-contractual". The only methods that would be allowed to throw a "contractual" InvalidOperationException would be those that were declared as doing so, and for the Add method (or any other) to call such methods, it would have to either enclose them in a try/catch block, a block or code structure which would indicate that those contractual exceptions should propagate as contractual exceptions of the caller, or one which would indicate that they should propagate as non-contractual exceptions [for the latter two usages, the enclosing block in question could if desired be the method as a whole].
And OP's example is more problematic than this, he wants to catch and swallow InvalidCastException and NullReferenceException. Unlike exceptions thrown by using throw those should start life as buggy. For syntax like the proposed one to be safe there should exist a kind of casts that generates non-buggy exceptions. Something like

C#
int winOpacity = try trycast<int>(Microsoft.Win32.Registry.GetValue(_regKey, "Opacity", null)) catch 100;
For the latter example, a variation of trycast which could handle a default would be better. On the other hand, for something like getting a value from an IDictionary, it would be helpful to have a method that could support covariance but easily allow the caller to cleanly handle a non-existent item (the TryGetValue pattern doesn't work with covariance). A framework whose calling convention was designed around contractual/non-contractual exceptions could avoid using expensive exception throwing mechanisms for contractual exceptions, thus allowing efficient "GetValue or else" code.
Jan 14, 2015 at 6:53 AM
supercat wrote:
and for the Add method (or any other) to call such methods, it would have to either enclose them in a try/catch block, a block or code structure which would indicate that those contractual exceptions should propagate as contractual exceptions of the caller, or one which would indicate that they should propagate as non-contractual exceptions
And, like I said in my previous post, this is yet another feature that needs to be added, yet another feature the developer has to learn to use properly. Do you think that this will improve exception handling or will just replace one set of problems with another? Anyway, all this is purely theoretical since it's very unlikely that we'll ever see something like this in C#. I know, I know, ramblings...
For the latter example, a variation of trycast which could handle a default would be better.
As in:
int y = x as int? ?? 42;
On the other hand, for something like getting a value from an IDictionary, it would be helpful to have a method that could support covariance but easily allow the caller to cleanly handle a non-existent item (the TryGetValue pattern doesn't work with covariance). A framework whose calling convention was designed around contractual/non-contractual exceptions could avoid using expensive exception throwing mechanisms for contractual exceptions, thus allowing efficient "GetValue or else" code.
There are other ways to achieve this, like allowing conversions for out parameters or using an option type for return. Probably now you'll come up with another example where out parameters and option types do not solve who knows what problem. I suppose I'll just leave it here otherwise this thread will never end. Hopefully now people who try to read through this thread have a better chance to understand what you were rambling about.