Raymond Chen's take on so-called zero cost exceptions

H. S. Teoh hsteoh at quickfur.ath.cx
Tue Mar 1 06:44:05 UTC 2022


On Mon, Feb 28, 2022 at 11:01:46PM +0000, Guillaume Piolat via Digitalmars-d wrote:
> On Monday, 28 February 2022 at 20:33:17 UTC, Walter Bright wrote:
> > "The presence of exceptions means that the code generation is
> > subject to constraints that don’t show up explicitly in the code
> > generation
>
> In my C++ years, exceptions in combination with RAII were the best
> barrier of defense against leaks and bugs in error paths. Also they
> would allow C++ constructors to fail, and error codes didn't. Worse,
> with error codes, people routinely conflated runtime errors and
> unrecoverable errors.  Performance is imo a false concern here since
> 1. either code that should be fast is devoid of eror handling in the
> first place 2. correctness of whole codebases is at stake 3. you can
> always make a correct program faster, but there will be noone to
> realize the incorrect program is incorrect.

IIRC, we had this discussion before some time ago, and Adam pointed out
that in D's early days it used to have its own exception-handling
implementation that involved passing exception status via a spare
register, supposedly faster than the baroque C++-style libunwind /
(whatever the Windows equivalent is) implementation. But later on, in
the name of C++ compatibility, that got replaced with libunwind /
Windows EH.

My point is, if you're dealing with code that may fail, you've got to
handle the error case *somehow*. Whether it's via a return code, or
libunwind, or passing some status in a spare register that the compiler
automatically inserts a check for.  The syntax is really irrelevant.
Whether you write:

	void mayFail() { throw new Exception(""); }

	void myFunc() {
		MyObj obj;
		mayFail();
		...
		// obj.dtor invoked
	}

or:

	int mayFail() { return ERROR; }

	void myFunc() {
		MyObj obj;
		if (mayFail() == ERROR) // returns error status
			goto EXIT;
		...
	EXIT:
		// obj.dtor invoked
	}

the semantics are essentially the same.  If one implementation of
exceptions is not as performant, why can't we switch to a more efficient
implementation?  After all, the compiler can, in theory, implement
`throw` in the first code snippet above by lowering it into the
equivalent of the second code snippet. Say, by using a spare register to
indicate the error (if mayFail returns a value besides its error
status).

The actual implementation of how exceptions are handled isn't really
tied to the surface syntax of the program.  One way or another you need
to handle the error condition somehow; what about exceptions makes it
fundamentally less efficient than handling an error code?

If error codes are somehow fundamentally more efficient, why can't the
compiler just rewrite throwing functions into functions that return
error codes, with the compiler inserting error code checks into the
caller as needed?


T

-- 
Why waste time learning, when ignorance is instantaneous? -- Hobbes, from Calvin & Hobbes


More information about the Digitalmars-d mailing list