On 04/03/2015 08:55, Ivan Timokhin wrote:
     void main()
     {
         auto arr = RCArray!int([0]);
         foo(arr, arr[0]);
     }

     void foo(ref RCArray!int arr, ref int val)
     {
         {
             auto copy = arr; //arr's (and copy's) reference counts are both 2
             arr = RCArray!int([]); // There is another owner, so arr
                                    // forgets about the old payload
         } // Last owner of the array ('copy') gets destroyed and happily
           // frees the payload.
         val = 3; // Oops.
     }

We could prevent reassignment of arr while val is alive, but perhaps still allow mutation of existing elements through arr.

I've changed Marc Schütz's example to explore this:

void main() {
    auto a = RCArray!int([5]); // a's refcount is now 1
    foo(a, a[0]); // pass by ref
}
void foo(ref RCArray!int a, ref int t) {
    a[0] = 4; // ok
    a = RCArray!int([]); // drop the old a
    t = 3; // oops, t is gone
}

I think Rust would enforce that either a *or* t can be mutably borrowed at once (and for a, t can't even be immutably-borrowed). Without designing a system, in theory foo is OK if a is const, but that prevents a[0] = 4. This could be allowed as long as a is not reassigned (i.e. a is head-const).

To support RCDynamicArray that supports appending and resizing, these operations also need to be excluded, whilst potentially allowing existing elements to be mutated.

(I've seen Andrei's solution for the above example, but it doesn't work for Ivan Timokhin's code, and for the former it can be non-ideal).

Perhaps a parameter attribute similar to head-const (but somehow configurable by the container author) could enforce this. The author of foo would need to use this attribute for a. The container could mark the safe mutation operations with this attribute.

Just an idea. I haven't considered other types of container, maybe it would help those also.

Reply via email to