Thread overview
[phobos] Drought of functions that throw exceptions
Oct 31, 2018
Richard Palme
Nov 01, 2018
Don Clugston
Nov 01, 2018
Richard Palme
Nov 01, 2018
Jonathan M Davis
Nov 02, 2018
Richard Palme
October 31, 2018
Is there a reason why so few functions in phobos throw exceptions? For example there is std.bitmanip.BitArray.flip that gets an index as argument and flips the bit that the index references, and this function does not throw an exception when given an invalid argument.

I'd be willing to fix this, but first I wanted to ask if there might be a reason for this. I think that throwing an exception should be preferable to a segmentation fault (which happens in the case of BitArray.flip).
_______________________________________________
phobos mailing list
phobos@puremagic.com
http://lists.puremagic.com/mailman/listinfo/phobos


November 01, 2018
Absolutely there is a reason. Exceptions are very expensive, especially in
low-level functions. In the situation you're talking about, it's a simple
logic error in the calling code. That situation will never happen in
bug-free code.
This is very different from the situation with something like a file
operation where "disk full" is a genuine exceptional situation.



On Thu, 1 Nov 2018 at 09:02, Richard Palme via phobos <phobos@puremagic.com> wrote:

> Is there a reason why so few functions in phobos throw exceptions? For example there is std.bitmanip.BitArray.flip that gets an index as argument and flips the bit that the index references, and this function does not throw an exception when given an invalid argument.
>
> I'd be willing to fix this, but first I wanted to ask if there
> might be a reason for this. I think that throwing an exception
> should be preferable to a segmentation fault (which happens in
> the case of BitArray.flip).
> _______________________________________________
> phobos mailing list
> phobos@puremagic.com
> http://lists.puremagic.com/mailman/listinfo/phobos
>


November 01, 2018
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
}
else
{
    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.
_______________________________________________
phobos mailing list
phobos@puremagic.com
http://lists.puremagic.com/mailman/listinfo/phobos


November 01, 2018
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
> }
> else
> {
>      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
phobos@puremagic.com
http://lists.puremagic.com/mailman/listinfo/phobos


November 02, 2018
On Thursday, 1 November 2018 at 12:50:19 UTC, Jonathan M Davis wrote:
> 

Thanks for your detailed answer. I didn't know the difference between errors and exceptions, but now I do.
_______________________________________________
phobos mailing list
phobos@puremagic.com
http://lists.puremagic.com/mailman/listinfo/phobos