On Thursday, 6 November 2014 at 08:30:22 UTC, Ola Fosheim Grøstad wrote:
It has been argued that exceptions are too slow in D to propagate regular errors and should just be used for the truly exceptional case. Then there should be a faster, but equally convenient alternative for regular errors.

In Go you "solve" the problem by returning tuples:
(returnvalue,errorcode) = function_call();

That is annoying. I'd rather see an implicit error code by having "return error(value)" be a builtin.


The basic idea is have a register based errno with language support:

1. On amd64 you designate one "caller save" SIMD register to error propagation.

2. Function signatures can specify if a return value:
- never provide errors
- provide errors that must be handled
- provide errors that can be ignored

3. The language checks if all mandatory errors are handled.

4. Functions called are only allowed to write non-zero values to the error register on return.

The language then provide constructs for dealing with errors:

// ignore error values, the compiler does not check
// errors until after func2() is executed (like opengl)

tryall {
    value = func1();
    value += func2();
}
catcherror{ … }

value = func(3);
if error { print_error(error); }
// error is cleared here by the compiler

value = func_optional_error();

// error is cleared here before calling a function
// that returns an error

value = func4();

I've been in your shoes before, wondering why there aren't better mechanisms for error handling. I've changed my view over time and let me explain why.

First, D has the capability to generate code that uses error codes via registers or some global variable (note: I wouldn't specify that a compiler should use a certain register for error codes, the compiler is smart and will decide the best way to do that). So I believe what you're looking for is a standard mechanism for functions to return errors and for the language to support that standard with a nice syntax. I don't think this is a bad idea, but this isn't really necessary since you can already do these things, maybe in a more verbose syntax, but you can do them without modifying the current language.

One thing I like about your suggestion is you can specify if a function's error code should be verified to be handled at compile time. It would be nice as a library writer if you could specify that the error MUST be handled by the caller. That way you have some protection that users will use your functions correctly.

Now back to Exceptions. I wanted to address your concern (and everyone else's) about exceptions being "slow". There are a lot of different opinions on this but over time I've "evolved" my view on them to some ideas that have been working for me for a while. The first idea is when to throw an exception...easy

A function should throw an exception if it CAN NOT perform the action indicated by it's name.

If a function named "write" fails to write, it should throw an exception. So what about functions that want to return error codes instead. What I do is prefix the function with "try". You don't have to do that, but it helps me personally keep track of what functions require explicit error checking. A function named "tryWrite" lets the user know the function may not write and they need to check somehow whether or not it failed.

Typically in the "normal operation" of a program, especially one you want designed to run fast, you will NEVER THROW AN EXCEPTION. An exception being thrown isn't typically used as normal "control flow". An exception is typically used to indicate an "environment error". That's why it's OK that they are so slow and expensive. You don't want to be throwing and catching exceptions all over the place, but when you do have an exception you want to capture as much info as possible even it if incurs a huge runtime cost.

A function that returns error in "normal program operation" should use the "try" mechanism and a function that always succeeds unless some type of environmental error occurs can just throw an exception.

Reply via email to