On Thursday, 6 September 2018 at 14:39:12 UTC, Andrei Alexandrescu wrote:
Second, it does pay to keep abreast other languages. I had no idea (and am quite ashamed of it) that Java also has chained exceptions:

https://www.geeksforgeeks.org/chained-exceptions-java/

Now I'm surprised... is there a language (except C++) that supports exceptions that does _not_ have it?
Java: getCause()
C#: InnerException
PHP: getPrevious()
...

They implement them manually, i.e. the user who throws a new exception would need to pass the existing exception (or exception chain) as an argument to the new exception's constructor. Otherwise, an exception thrown from a catch/finally block obliterates the existing exception and replaces it with the new one:

https://stackoverflow.com/questions/3779285/exception-thrown-in-catch-and-finally-clause

So chaining exceptions in Java is a nice complementary mechanism to compensate for that loss in information: when you throw, you have the chance to chain the current exception so it doesn't get ignored. Because of that, D's chained exceptions mechanism can be seen as an automated way of doing "the right thing" in Java.

We should study similarities and distinctions with Java's mechanism and discuss them in our documentation.

I think chained exception in D is semantically very different from other languages like Java.

In languages like Java or C# the exception chain has nothing to do with saving exceptions that are thrown in finally blocks. Instead the chain is used for a layer model. The "outer" exception is the higher level exception and the "inner" exception is the lower level cause of the higher level exception.

Often a low level exception is quite meaningless when thrown over multiple levels in the call stack. For example, imagine a program that uses a configuration file. While parsing the configuration, a misformatted number is encountered. If the NumberFormatException is propagated to the top level, it is basically useless for programmatic error handling.
This is much better:
ConfigurationException -> JsonParsingException -> NumberFormatException

The higher level exceptions are therefore directly caused by the lower level exception and always thrown _directly_ in the catch block where the lower level exception is catched and readily available. Not in a finally block and not indirectly in a function called from the catch block. Manually passing the inner exception to the constructor of the outer exception is trivial and IMO the right thing, because it's probably not always wanted.

Now in D, chained exceptions work differently.
The first exception that is thrown is deemed the "important" exception and later exceptions are simply chained to it. A direct semantic connection between the exceptions is not possible at all, since the later exception has no knowledge about the first exception at all. It also means that the order of the exceptions is reversed. The first exception is the "outer" exception which is the exact opposite of how it is meant in Java.

When handling an exception, it's not clear at all what those additional exceptions mean and how they should be handled.

Personally I find the Java/C# model much more useful.

---
Tobias

Reply via email to