Thread overview
[Warning] Side effects in asserts
Jul 23, 2004
Stewart Gordon
Jul 23, 2004
Kris
Jul 26, 2004
Stewart Gordon
Jul 26, 2004
Kris
Jul 26, 2004
Stewart Gordon
Jul 23, 2004
Sean Kelly
July 23, 2004
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.
July 23, 2004
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.


July 23, 2004
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


July 26, 2004
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()
<snip>

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.
July 26, 2004
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
it
> > does identify another good reason for the existence of version()
> <snip>
>
> 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.


July 26, 2004
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.
<snip>

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.