ANSI assert

Karl Heuer karl at haddock.ima.isc.com
Wed Sep 12 12:03:22 AEST 1990


[We agree that ANSI assert() forbids the evaluation of the argument, so the
fun part of this discussion now belongs in alt.lang.cfutures instead.  I'm
redirecting followups.  --kwzh]

In article <3726 at goanna.cs.rmit.oz.au> ok at goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
>In article <1428 at proto.COM>, joe at proto.COM (Joe Huffman) writes:
>>[The ANSI definition for ``assert'' breaks my code that does this:]
>>   assert(i++ < limit);
>
>Your code is *ALREADY* broken.  The ``de facto'' standard in UNIX has been
>[to not evaluate the arg if NDEBUG is enabled] for a long time.  For many
>people it has been important that the test *not* be evaluated when NDEBUG is
>defined; if the tests are cheap enough that you want them to be done anyway
>you would be rather silly to do all that work and not take advantage of it!

It's not the *tests* that he wants done unconditionally; just the side
effects.  I discovered (and reported) that an early Draft of the Standard
neglected to specify whether the side effects were forbidden, permitted, or
required; I was personally hoping for ``required'' so that calls like the
above would be sensible.  I backed down when somebody pointed out the
>	assert(very_costly_checking_call());
you mentioned.

>Quite apart from assert being a macro rather than a function,

Irrelevant, since ANSI macros are ``safe'' unless otherwise noted, and it
would have been easy enough to make this one safe if ANSI had required it.

>Supposed to be *pure* boolean formulas...comments about the code, not an
>integral part of it...

That's the common convention, but I think the ``assert(getchar() == '\n')''
example demonstrates that it could be useful to violate it.  The alternative
of ``c = getchar(); assert(c == '\n');'' may well trigger the warning
``variable c assigned but not used''.  And ``#ifdef NDEBUG   (void)getchar();
#else   assert(getchar()=='\n');   #endif'' is too bulky; it's exactly the
sort of thing for which macros are designed--so why not encapsulate it in a
macro, as long as it's not called ``assert''?

Remember my posting of 14-Jan-1988 where I talked about assert()?  I've gotten
nine replies over the last two years and eight months; they don't seem to be
trickling in anymore, so I guess it's time to post the summary: The consensus
is that a change in semantics would have to be accompanied by a change in
name, even though few people admitted to invoking complex (but pure) functions
from an assert().

So anyway, I would now propose the following:

In addition to ``assert'', <assert.h> shall define the macro ``require'',
which always evaluates its argument for side effects, whether or not NDEBUG is
set.  If the argument is true (compares unequal to zero), then the macro
returns no value.  Else, if the NDEBUG macro is not defined, then a message is
printed and the abort() function is invoked.  Else, the behavior is undefined.

The last clause makes require() useful for pure expressions, too.  The
rationale is that the code has been tested without NDEBUG and verified to be
correct; defining NDEBUG means that the user is ready for optimization.
Saying that the behavior is undefined gives the compiler license to assume
that the assertion is indeed true, and it may be able to generate better
subsequent code.  It is noted that current optimizer technology won't handle
anything much more complex than ``require(x == 3)'' or ``require(x == y)'',
but we can hope that this will be improved.  For example, one might be able to
use this to inform a vectoring compiler that two arrays are non-overlapping.

>-- 
>Heuer's Law:  Any feature is a bug unless it can be turned off.

(I *knew* that would be showing up in a .signature within the week.)

Karl W. Z. Heuer (karl at kelp.ima.isc.com or ima!kelp!karl), The Walking Lint



More information about the Comp.std.c mailing list