karl@haddock.ima.isc.com (Karl Heuer) (09/12/90)
[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@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: >In article <1428@proto.COM>, joe@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@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint