2.011 invariant question

Sönke Ludwig ludwig at informatik_dot_uni-luebeck.de
Sat Feb 23 04:59:26 PST 2008


Janice Caron wrote:
 > Looks like a bug to me.

I'd think so, too.

> 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.
> 

That's right, of course, that this is a problem of lifetime. The difference
is that objects on the heap are garbage collected and their lifetime is
always long enough not to disturb invariant references (as long as delete
is not used explicitly).

The reason why I think that maybe there should be a difference between
invariant and non-invariant stack values is that when you take a reference
to a non-invariant value, you are not guaranteed to get the same data when
you dereference it later anyways. Invariant, however, makes that claim. So
ideally, whenever you get hold of a reference/pointer to invariant data, you 
should be able to store it and assume that it will never change.
Is change in semantics (work on the compiler) is worth it in this case?
I don't know. I can live with it this way, too - but nevertheless, it would
be a similar generalization like with full-closures (and might be nice even
for non-invariant data, or maybe it's overkill).

> 
> 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.
> 

Just wanted to say that the array is used here like a stack.

> 
>> (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.
> 

Right, I didn't think of incremental string building.. but maybe
"always reallocate on length = X;" would be an OK solution?

> 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.

... but it's particularly bad when the invariant promise is broken at
the same time.

> 
> 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/.
> 

I think that if it's fixed, it has to be done transparently or it my be
difficult to explain why s = s ~ "x"; is allowed but s ~= "x"; is not.



More information about the Digitalmars-d mailing list