- To: bbigby at rochester dot rr dot com
- Subject: Re: Exception-Handling for C
- From: Richard Stallman <rms at gnu dot org>
- Date: Sat, 19 Feb 2000 05:34:36 -0700 (MST)
- References: <200001032236.RAA03055@mescaline.gnu.org> <200002061341.GAA13985@aztec.santafe.edu> <389E3ABF.98A23475@rochester.rr.com> <200002072357.QAA15823@aztec.santafe.edu> <389F7D26.B320C906@rochester.rr.com>
- Reply-to: rms at gnu dot org
How about taking part of this message, the part which is about
design-by-contract, and mailing it to gcc@gcc.gnu.org? Maybe someone
there will get interested in adding those features to GCC.
Say that I asked you to send it there.
Sender: bbigby@gnu.org
Date: Mon, 07 Feb 2000 21:19:18 -0500
From: "Bruce W. Bigby" <bbigby@rochester.rr.com>
X-Accept-Language: en
To: rms@gnu.org
Subject: Re: Exception-Handling for C
Content-Type: text/plain; charset=us-ascii
Content-Length: 6878
Richard Stallman wrote:
>
> GEF contains a set of man pages which explain its usage. If you have a
> RedHat Linux system,
>
> I use Debian, one reason being that they call the system GNU/Linux.
> Could you please call it GNU/Linux?
>
I should have said the RedHat Linux Distribution, which is the official
name for RedHat's product. I don't mean to take any credit away from
GNU. I certainly am aware of GNU and have been using GNU's tools for
many years. Heck, I used to use Emacs back when I was an undergrad at
MIT. I really only wish to use one name--not two. I mean no disrespect.
I think that the solution to all of this is to simply use one name to
refer to the entire collection of software. For example, I could have
said get the RedHat distribution with neither a reference to GNU nor
Linux. GNU certainly receives its claim to fame when people refer to the
"GNU utilities" or the "GNU C Compiler". Everyone who cares about GNU
software knows about GNU software. I just can't bring myself to say
GNU/Linux when I'm referring to an entire distribution. I need one word.
Care to recommend something? ;-)
> Anyway, I think you have answered my questions. Basically, GEF
> is implemented using macros, which is good in the sense that it
> can be portable; but it is not as clean for the user as something
> implemented in the C compiler--or do you disagree?
>
I absolutely agree that a compiler solution would be better. The
compiler would ensure that functions cannot call return/break from an
improper point, thereby screwing up the program's exception-handling
stack. Also, perhaps the compiler version would be a little more
efficient for the case when GEF is totally disabled. I'm not sure how
much more efficient. I didn't compare a program where GEF is disabled
versus the same program where it does not contain any GEF code. I may do
that some day. However, I went through great lengths to make GEF operate
as quickly as possible when disabled.
I hope that ANSI, some day, supports exception-handling and
Design-by-Contract in C. Perhaps GEF could be a model for the feature.
Note: GEF's features are more like Eiffel's than C++'s.
> Might you be interested in helping to add exception facilities to GCC
> for the C language? C++ already has them but the C front end provides
> no way to access those features.
>
You know, I honestly don't have the time to participate in such a
project (sigh). I work full-time at Xerox and have a family. I wish I
did have the time to devote to such an endeavor. I would just love it.
However, I would certainly be able to give my $0.02 to an eager
programmer who is brave enough to tackle such a feature. GEF could serve
as a proof-of-concept.
Actually, the OSF CDE RPC package supports exception-handling. However,
it doesn't go as far as to support the "Design-by-Contract" features. I
don't recall how the rest of it compare's to GEF's exception-handling
features. I think GEF's features are more flexible and allows for much
better performance in programs that one "proves" to be correct.
> I am not sure what "design by contract" is, or assertion/contract
> checking, but I suspect that those should be considered separate
> features (at least for the user). Do you agree?
Actually, I think that the "Design-by-Contract" features should be
integral to the exception-handling. I read somewhere that one of the key
authors of Java had included a rudimentary facility for specifying
contracts but yanked it out at the last minute, because of time
pressures to get Java out into the public. He regrets that decision.
Contract/assertion checking support is key to ensuring that developers
write correct programs. When an assertion violation occurs, GEF calls
its default call-back function, which throws a default assertion
violation exception. An assertion is nothing more than a condition that
must be true. You basically use the gef_assert(boolean) macro to assert
some condition that must be true. The 'boolean' argument is any
expression that evalues to C true or false. Although C has a rudimentary
assert() statement, it is not connected to an exception-handling
facility, which it should be.
"Design by Contract" is the notion that the caller of a function
(client) and the function (server) share the responsibility of ensuring
the proper behavior of the function. Call this the contract of a
function. Take a simple SquareRoot function, which requires its input to
be 0, or greater, and ensures that the return value will be within a
certain error.
double
SquareRoot(double x) {
double answer;
gef_try {
answer = sqrt(x);
} gef_preconditions {
gef_assert(x >= 0.0);
} gef_postconditions {
gef_assert(fabs(answer * answer - x) <= 0.001);
} gef_end;
return(answer);
}
The contract is as follows: Providing that the input, x, to SquareRoot
is greater than, or equal to, 0, SquareRoot will return a value that is
the square root of x--call it y--such that the square of y does not
differ from x by more than 0.001. The contract specifies the
responsibilities of the caller as well as the callee.
Oh, by the way, GEF executes all of the statements in the gef_invariants
block, followed by all of the statements in the gef_preconditions block,
followed by those in the gef_try block, followed by the gef_catch block,
if an exception occurs in the gef_try block, followed by those in the
gef_finally block, followed by those in the gef_postconditions block,
followed by those in the gef_invariants block (again). However, only the
gef_try block, followed by a corresonding gef_end, are required in an
exception-handling block. The programmer need not specify a gef_try, if
he/she doesn't plan to handle an exception, or release resources.
Invariants do not apply in this function. However, you can use the
gef_invariants block for abstract data structures that contain
relationships that must always hold true upon entry to, and exit from, a
function.
For example, imagine that you have a dynamic array that may grow at
either end. This means that its lowerbound and upperbound may be any
integral value--negative, 0, or positive. No matter what happens to the
array, the upperbound of the array minus its lowerbound + 1 must always
be equal to the number of entries in the array. You can use the
gef_invariants block to specify conditions that must always be
true--thus the use of the term, "invariants".
It'd be neat, if someone could become familiar with GEF and use it as a
model for what exception-handling under C, and Posix systems, could look
like.
Thanks for responding. Let me know, if you find someone who is eager to
use the package in his/her programs and would like some info on it. I'm
more than eager to consult. :-)
--
Bruce W. Bigby
http://home.rochester.rr.com/bigbyofrocny
Do for others what you would want others to do for you.