|Posted by Jonathan M Davis|
in reply to Richard Palme
Posted in reply to Richard Palme
On Thursday, November 1, 2018 6:05:28 AM MDT Richard Palme via phobos wrote:
> On Thursday, 1 November 2018 at 08:42:28 UTC, Don Clugston wrote:
> > Absolutely there is a reason. Exceptions are very expensive, especially in low-level functions.
> Then I got a few follow-up questions (I hope this isn't the wrong
> place for beginner questions):
> 1. Why is it that arrays throw RangeExceptions? Shouldn't that be
> too costly too?
> 2. I might be wrong but I thought that in the following code
> example the additional cost is only the cost of one additional
> branch from the if statement, unless of course i >= length which
> should never happen.
> if (i < length)
> //do something
> throw new Exception();
> 3. When exceptions can't be used, then I guess the best way to
> ensure safety are pre and post contracts. But I actually don't
> know how to activate the contracts in phobos.
> I thought that maybe I have to build both phobos and dmd with
> $make -f posix.mak -j8 BUILD=debug
> but I just tried that and I don't think it worked.
Indexing an array does not throw a RangeException. There is no such thing in D. It throw an RangeError. So, you're program dies when it gets thrown. Yes, that incurs the extra cost of having the array bounds checked, but in order to guarantee that indexing an array is @safe, it's required (whereas in @system code with -release, the array bounds checking is removed). Either way, it's not at all the same as having full-blown exception handling. A lot of the exception handling code simply isn't set up for Errors, and Errors can be thrown from nothrow functions, because they aren't supposed to be caught. They're intended for fatal conditions such as logic errors or when resources that the program assumes are available and must be available for proper operation are not available (such as memory). Exceptions on the other hand are intended for recoverable conditions such as bad program input or system state.
In some cases, it makes sense to check for logic errors, and in some cases, it doesn't (efficiency often being the concern), but it doesn't makes sense to try to recover from them. It often makes sense to check for logic errors in debug code but not in release code (e.g. with assertions), whereas in other cases, it can be considered so vital that something not continue if a condition isn't true that the checks remain in place (which is the case with array bounds checking in @safe code, because they have to be in place to guarantee memory safety). So, whether the checks are in place or not can be a bit of an art, but regardless, they are _not_ exceptions.
Exceptions are only used in situations where it's reasonable for the code to fail - such as when the input to the program could be bad or when an operation depends on the state of the filesystem. Having such operations fail aren't bugs in the logic of the program, and so having them fail in a way that allows the program to respond and recover makes sense. This is completely different from operations such as indexing an array or dereferencing a pointer. The programmer has the ability to guarantee that such code is correct, and it's an error in the logic of the program if they're not. So, using exceptions for such operations is completely inappropriate.
As for adding additional checks for fatal error conditions, that is a bit of an art, and exactly when it should be done needs to be examined on a case by case basis, but if the result of a failure is a segfault, then that means that the CPU already caught the problem for you, and there's no need to add additional checks. Doing so would just be additional overhead. If a program does segfault, and it has core dumps enabled, it will have full information about where the failure occurred and can track the problem down. But regardless, it's a bug in the program that needs to be fixed and _not_ an error condition that the program should be trying to recover from, so exceptions are inappropriate.
- Jonathan M Davis
phobos mailing list