www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [Warning] Side effects in asserts

reply Stewart Gordon <smjg_1998 yahoo.com> writes:
There seems to be an idiom I've got a bit carried away with

     assert(DoSomething());

where DoSomething is some system call that returns non-zero to indicate 
that it's succeeded.  I recall it being used in winsamp.d, and possibly 
also some of the other examples.  It's a convenient way of doing a 
system call and making sure it's succeeded in one line.

Except that it isn't:

"Asserts evaluate the expression. If the result is false, an AssertError 
is thrown. If the result is true, then no exception is thrown. It is an 
error if the expression contains any side effects that the program 
depends on. The compiler may optionally not evaluate assert expressions 
at all. The result type of an assert expression is void. Asserts are a 
fundamental part of the Design by Contract support in D."

In other words, not only will it not check for failure in the release 
version, but it also probably won't evaluate the body of the assert at 
all, and so the system call necessary to the program won't happen.

So I thought I'd better warn you all before you get even more carried 
away with this bad idiom.  If you want to check if a system call has 
failed, use a real if statement or ?= expression.  This will also make 
it possible to throw an exception of choice rather than an AssertError, 
as you'll probably want to do anyway.

Let's see if I can get these cleaned up in time for SDWF 0.3....

Stewart.

-- 
My e-mail is valid but not my primary mailbox, aside from its being the 
unfortunate victim of intensive mail-bombing at the moment.  Please keep 
replies on the 'group where everyone may benefit.
Jul 23 2004
next sibling parent reply "Kris" <someidiot earthlink.dot.dot.dot.net> writes:
I've noticed that the compiler will leave anything that might have a
side-effect in place. That is, when asserts are disabled your DoSomething()
will still be in the code-line. This is both a blessing and a curse, but it
does identify another good reason for the existence of version()

- Kris


"Stewart Gordon" <smjg_1998 yahoo.com> wrote in message
news:cdrc9e$24u0$1 digitaldaemon.com...
 There seems to be an idiom I've got a bit carried away with

      assert(DoSomething());

 where DoSomething is some system call that returns non-zero to indicate
 that it's succeeded.  I recall it being used in winsamp.d, and possibly
 also some of the other examples.  It's a convenient way of doing a
 system call and making sure it's succeeded in one line.

 Except that it isn't:

 "Asserts evaluate the expression. If the result is false, an AssertError
 is thrown. If the result is true, then no exception is thrown. It is an
 error if the expression contains any side effects that the program
 depends on. The compiler may optionally not evaluate assert expressions
 at all. The result type of an assert expression is void. Asserts are a
 fundamental part of the Design by Contract support in D."

 In other words, not only will it not check for failure in the release
 version, but it also probably won't evaluate the body of the assert at
 all, and so the system call necessary to the program won't happen.

 So I thought I'd better warn you all before you get even more carried
 away with this bad idiom.  If you want to check if a system call has
 failed, use a real if statement or ?= expression.  This will also make
 it possible to throw an exception of choice rather than an AssertError,
 as you'll probably want to do anyway.

 Let's see if I can get these cleaned up in time for SDWF 0.3....

 Stewart.

 --
 My e-mail is valid but not my primary mailbox, aside from its being the
 unfortunate victim of intensive mail-bombing at the moment.  Please keep
 replies on the 'group where everyone may benefit.

Jul 23 2004
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Kris wrote:
 I've noticed that the compiler will leave anything that might have a
 side-effect in place.

Maybe, but it's certainly not required to. Indeed, if it really wants to generate efficient release code then it would probably leave it out.
 That is, when asserts are disabled your DoSomething()
 will still be in the code-line. This is both a blessing and a curse, but it
 does identify another good reason for the existence of version()

I'm not sure what you mean. How would versions get around this? Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
Jul 26 2004
parent reply "Kris" <someidiot earthlink.dot.dot.dot.net> writes:
Now I'm trying to recall the context ... uhhh (clickety clickety whirrr ...)

Ah, right. I meant that since assert() will potentially leave
side-effect-causers in the code (such as a function call), a construct such
as version(){} is needed in the language, so one can be explicit about
whether you really do have side effects or not. That is, wrapping the
assert() inside a version(), or a debug() at least allows you to be explicit
about removing the assert() and all other checks. The assert() by itself is
not sufficiently explicit.

- Kris


"Stewart Gordon" <smjg_1998 yahoo.com> wrote in message
news:ce2j5j$mfu$1 digitaldaemon.com...
 Kris wrote:
 I've noticed that the compiler will leave anything that might have a
 side-effect in place.

Maybe, but it's certainly not required to. Indeed, if it really wants to generate efficient release code then it would probably leave it out.
 That is, when asserts are disabled your DoSomething()
 will still be in the code-line. This is both a blessing and a curse, but


 does identify another good reason for the existence of version()

I'm not sure what you mean. How would versions get around this? Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.

Jul 26 2004
parent Stewart Gordon <smjg_1998 yahoo.com> writes:
Kris wrote:

 Now I'm trying to recall the context ... uhhh (clickety clickety whirrr ...)
 
 Ah, right. I meant that since assert() will potentially leave
 side-effect-causers in the code (such as a function call), a construct such
 as version(){} is needed in the language, so one can be explicit about
 whether you really do have side effects or not. That is, wrapping the
 assert() inside a version(), or a debug() at least allows you to be explicit
 about removing the assert() and all other checks. The assert() by itself is
 not sufficiently explicit.

Release and debug aren't the only compilation modes. There's the default mode - DBC, asserts and ABC enabled, but debug blocks not. And at the moment, we don't (according to the docs) have a version identifier for release. And anyway, it would keep the code concise to just do something like // system call with no side effect assert (CheckSomething()); // system call with side effect if (!DoSomething()) assert(false); // or if (!DoSomething()) throw new SomeException; A version block around the first assert would be pointless, as it would be similar to "language features for the purpose of compensating for primitive compiler technology". Stewart. -- My e-mail is valid but not my primary mailbox, aside from its being the unfortunate victim of intensive mail-bombing at the moment. Please keep replies on the 'group where everyone may benefit.
Jul 26 2004
prev sibling parent Sean Kelly <sean f4.ca> writes:
In article <cdrc9e$24u0$1 digitaldaemon.com>, Stewart Gordon says...
There seems to be an idiom I've got a bit carried away with

     assert(DoSomething());

Yup. Same problem in C/C++. I ended up making a new macro for this situation: #ifdef NDEBUG inline void predicate( bool ) {} #else inline void predicate( bool exp ) { assert( exp ); } #endif You could do something similar in D. Sean
Jul 23 2004