[Cfp-interest] draft of syntax discussion for C committee

David Hough CFP pcfp at oakapple.net
Thu Jun 5 16:26:57 PDT 2014



Alternate Exception Handling Syntax


How fast you can drive a car depends on how fast you can stop


Alternate Exception Handling is specified in Chapter 8 of IEEE 754-2008.
It's a series of recommendations to programming environments about what
kinds of facilities to provide in languages for portable numeric 
programming.      Some of these recommendations have to do with changes
of control flow, and the best syntax to propose for these is the subject
of this note.

The overall idea is that the normal case should go as fast as possible
for performance reasons, so testing for exceptional conditions should not
slow it down.    Likewise the normal case should terminate as quickly as
possible when exceptional conditions arise, lest (particularly in a loop
terminated by a floating-point conditional test) it get into an expensive
or infinite loop.

The previous IEEE 754-1985 recommended traps on exceptions.    These are
implemented in most IEEE 754 hardware systems, but they are so low level
that they are not used
much except for debugging, where they can be easily used to stop the 
program altogether.    It is not possible to write portable code to
handle a hardware trap and continue in any useful way.    
But if free testing for exceptions is built into the hardware without
slowing down the normal case, how can we make it available to the application
programmer?

Thus 754-2008
recommends alternate exception handling at a level that is meaningful
to the application programmer, leaving the details of hardware trapping
to the compiler, run time library, and operating system.     It is also
possible to implement 754-2008 alternate exception handling without hardware
traps, but with significant performance penalties for either the normal case 
or exceptional case.

The general programming paradigm as it might be naturally
expressed in many languages is

try {
 normal case code...
}
catch (floating-point exception-list) {
 exceptional case code...
}
 following code...

The normal case code is executed; if any of the exceptions in the list arises,
the normal case code is interrupted as quickly as possible (and thus its
output variables may be in an indeterminate state) and the exceptional case
code is executed.      In either case, after the normal case terminates
normally or the exceptional case terminates, the "following code" is executed.

There are versions of try/catch in standard C++, java, C#, perl, php, python,
matlab. 
There are try/catch extensions in at least two Fortran compilers 
targeting .NET applications.
These are all very similar but each slightly different.    

ruby has a somewhat
more different version; any begin/end compound statement may have one or
more rescue clauses corresponding to catch; there is no explicit try keyword.

Naturally, for C, the closest analog is C++.    
C++ catch clauses have as
arguments a parameter and its type.     The parameter is set by the system
for standard exceptions and by the programmer for programmer-defined exceptions
generated with the throw() function; the catch clause is matched to the
throw by the type of the thrown object.     There is also a catch(...)
syntax to catch all unspecified exceptions.

Unlike most of the exceptions for which try/catch was designed, some 
floating-point exceptions arise frequently - inexact especially and 
underflow in some programs - and the default treatment of continuing
execution with a prescribed result and raising a flag should be in force
if no alternate treatment is called out in a catch clause.

So much of C++ exception handling is unneeded to support 754-2008
floating-point alternate exception handling:
 * no need to throw()
 * no need to catch(...) unspecified exceptions
 * catch clause is matched by exception rather than type -
   in standard C, exceptions receive names in <fenv.h> like FE_INVALID

Furthermore there is another difference important for performance:
whereas in C++ the code in the try clause is compiled without reference 
to subsequent catch clauses, for floating-point purposes it is usually
desirable or necessary to know which exceptions are to be trapped.
If the implementation is to be by traps, a trap handler has to be set
up before the try clause and torn down on exit; if the implementation
is to be by conditional branches on operands and results, that code
has to be generated inline in the try clause.     As a consequence,
a strictly one-pass C
compiler that could not exploit hardware traps would not be able to
implement alternate exception handling fully and efficiently - it would
have to test exception flags at the end of the try clause, and rely
on the programmer to code in such a way that no expensive or infinite
loop arises in the try clause if an exception arises.    
Furthermore, a little-appreciated but important requirement of 754-1985
and 754-2008 is that exact underflow conditions must be detected by
trapping (1985) or alternate exception handling (2008) 
if enabled, even though the underflow flag is not raised (and thus can't be
used to detect exact underflow).

The point of this very long preamble is that, syntactically,  the catch
clause for floating-point exceptions should be seen before the try clause
rather than afterward as it is in most languages.    One can imagine
having the catch before, in which case the keyword should perhaps be
different:

catch_fe( exception-list) {
 exceptional case code...
}
try {
 normal case code...
}

or having it within the try clause:

try {
catch_fe( exception-list) {
 exceptional case code...
}
 normal case code...
}

or allowing an optional red-flag pragma to warn one-pass compilers:

try {
#pragma STDC FENV_CATCH_AHEAD exception-list
 normal case code...
}
catch_fe (floating-point exception-list) {
 exceptional case code...
}

But having to specify the same exception-list in two different places
seems error-prone.


One result of preserving some form of try/catch syntax is that 
floating-point
exception handling could be added to C++ with minimal syntactic effort, 
and most of
C++ exception handling could be added to C with minimal syntactic effort.
If that compatibility is deemed to be of low value, 
then there are other alternatives.


First, since the explicit try clause is not really needed, one could
define catch_fe clauses for any compound statement delimited by curly
brackets, and instead of adding a catch_fe keyword, it could be a 
variety of pragma:


{
{
#pragma STDC FENV_CATCH exception-list 
 exceptional case code...
}
 normal case code...
}

It's exactly the same try/catch semantics as what we started with, 
but in syntax not particularly close to C++ or anybody else's try/catch.
However it does match other #pragma's 
having scope in compound statements or in files,
that are already in C,
or are already in
previous floating-point extension reports going through the approval
process, or that are being considered to control other aspects
of floating-point code generation.


While the C floating-point extensions discussion group could pursue any of
these directions and report the results to the C committee,
we'd appreciate early feedback and direction from the C committee
as to which seems the most acceptable, or whether there's some better
C-like way to express the semantics.    The semantic content is pretty
much the same with all, but the syntax possibilities vary widely.


More information about the Cfp-interest mailing list