Asserts and side effects

Denis Koroskin 2korden at gmail.com
Mon Nov 30 05:06:39 PST 2009


On Mon, 30 Nov 2009 15:46:45 +0300, KennyTM~ <kennytm at gmail.com> wrote:

> On Nov 30, 09 19:15, Denis Koroskin wrote:
>> On Mon, 30 Nov 2009 13:52:48 +0300, Lars T. Kyllingstad
>> <public at kyllingen.nospamnet> wrote:
>>
>>> The following is a quote from a comment in the Reddit post about
>>> asserts that Walter just linked to:
>>>
>>> "Asserts are not without pitfalls, though. If you aren't careful,
>>> what to put in the asserts, the program could behave differently"
>>>
>>> A trivial example of this is:
>>>
>>> int i;
>>> write(i);
>>> assert (++i == 1);
>>> write(i);
>>>
>>> Normally, this program prints "01", but in release mode it prints
>>> "00". Asserts should never change the behaviour of a program, but
>>> currently it is up to the programmer to verify that this is in fact
>>> the case.
>>>
>>> Would it be possible (and desirable) for the D compiler to statically
>>> check that asserts have no side effects?
>>>
>>> -Lars
>>
>> Compiler must do full code flow analysis to do that:
>>
>> bool foo(); // no body or body is very complicated
>>
>> void main()
>> {
>> assert(foo()); // okay to call or not?
>> }
>>
>> I believe this is doable with introduction of a new attribute -
>> @hasNoSideEffects (shorter name would be better) with the following  
>> rules:
>>
>> - @hasNoSideEffects functions cannot modify variables outside of a
>> function scope. It means that they can read globals, but can not get a
>> non-const reference (or pointer) to them.
>>
>> - @hasNoSideEffects can only call other @hasNoSideEffects functions
>>
>> - Body of an assert check has a @hasNoSideEffects attribute, and follows
>> the same rules.
>>
>> @pure is a subclass of @hasNoSideEffects. @hasNoSideEffects functions
>> are also very useful for various performance optimizations.
>>
>> I think it is as valid attribute as @pure (even though it might affect
>> code generation outside of a function body due to open optimization
>> opportunities).
>>
>> Perhaps @pure semantics should be changed to @hasNoSideEffects (i.e.
>> allow non-invariant input arguments and allow accessing globals).
>>
>> It will lose a memoization ability, but to be honest I don't think
>> memoization needs to be implemented based on @pure attribute alone. For
>> example, std.math.pow() is @pure, but is it worth memoizing? I think
>> it's programmer who should decide what functions are expensive enough to
>> be memoized, and these should be marked as such explicitly (@memoizable,
>> or something).
>
> Can you give an example which @hasNoSideEffects but not @pure?

Sure:

// can't be pure because pure functions
// accept only immutable args
@hasNoSideEffects int deref(int* ptr)
{
     return *ptr;
}

class Array
{
     @hasNoSideEffects int length() const
     {
         return _array.length;
     }

     @hasNoSideEffects ref T opIndex(size_t index)
     {
         return _array[index];
     }

     private T[] _array;
}

Array!(int) array = ...;
for (int i = 0; i < array.length(); ++i) {
     int v1 = array[i]; //
     int v2 = array[i];
     int v3 = array[i];
}

It the example above, array.length and i-th value are only evaluated once,  
because length and opIndex both have no side effects.

BTW, any class invariant should also be marked as @hasNoSideEffects  
implicitly and checked accordingly.

I think @pure attribute is too restrictive to be useful. I believe there  
are an order of magnitude more functions that could be marked as  
@hasNoSideEffects than those that could be marked as @pure.



More information about the Digitalmars-d mailing list