2.011 invariant question

Janice Caron caron800 at googlemail.com
Sat Feb 23 04:29:42 PST 2008


On 23/02/2008, Sönke Ludwig <ludwig at informatik_dot_uni-luebeck.de> wrote:
>  Maybe I'm missing something - but I don't get what's the reasoning behind the
>  following error?
>
>  -----------------
>  struct FOO {
>         invariant int x;
>         int y;
>  }
>
>  int main()
>  {
>         FOO bar;
>         bar.y = 2;
>         return 0;
>  }
>  -----------------
>  gives the error:
>  test4.d(9): variable test4.main.bar cannot modify struct with immutable members

Looks like a bug to me.


>  But on a related note on invariant - I think I have mentioned this already at
>  some point - but just in case. If 'invariant' should be theoretically safe in
>  the future, invariant values may not be allowed on the stack (the stack is never
>  invariant)

That's not quite correct. In a declaration like:

    invariant int x = whatever;

x will be invariant, and on the stack, and this is perfectly
reasonable and safe because it's a local variable, and so won't exist
when the function goes out of scope. If you're going to say "the stack
is never invariant" because it gets reused, then you might as well say
"the heap is never invariant", because it, too, gets reused. It's all
about understanding the lifetime of an object.


>  int main()
>  {
>         invariant(int)[] arr = [1, 2, 3];
>         invariant(int)* someref = &arr[2];
>         arr.length = 2;
>         arr ~= 4;
>         writefln("array: %s - %s", arr, *someref);
>         return 0;
>  }
>  -----------------
>
>  prints "array: [1 2 4] - 4"
>
>  So currently any references to invariant data can be changed legally with
>  this stack principle.


This has nothing to do with the stack. The same bug would manifest if
arr were on the heap.

It certainly does look like a bug though.


> (Invariant arrays could be fixed by always reallocating on
>  opCatAssign)

No, that would be too inefficient. Appending to the end of a buffer is
too common an operation to demand a reallocation every time. It is
/much/ more sensible to allow the compiler to know the "reserved" size
of an array, and only reallocate if the "reserved" area becomes full.

I think the same problem will arise if you say

    arr = arr[0..2];

instead of

    arr.length = 2;

I'm fairly sure this happens because arr.ptr points to the first byte
of a resizable buffer. I'm fairly sure this is because ~=
(opCatAssign) is making the /assumption/ that the array is unique. As
has been mentioned before, there is no way to express uniqueness in D.

The problem also exists in non-invariant arrays too. Both mutable and
const arrays suffer from the same effect, whenever the arrays are
non-unique.

Perhaps D could partially work around the problem by banning ~= on all
but mutable arrays (although as noted, that still wouldn't solve it
completely), and then code which wants to append to a buffer would
have to declare the buffer mutable, but could still use assumeUnique()
to return it. But I'm not sure I like that idea.

I think it just needs to be extremely well documented: /Do not use ~=
on a non-unique array/.




More information about the Digitalmars-d mailing list