Asserts and side effects

Don nospam at nospam.com
Mon Nov 30 05:41:35 PST 2009


Denis Koroskin wrote:
> 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.

Interestingly, provided source code is available, the CTFE engine can 
execute @hasNoSideEffects functions. It doesn't require 'pure'.




More information about the Digitalmars-d mailing list