RCArray is unsafe

via Digitalmars-d digitalmars-d at puremagic.com
Sun Mar 1 07:44:47 PST 2015


Walter posted an example implementation of a reference counted 
array [1], that utilizes the features introduced in DIP25 [2]. 
Then, in the threads about reference counted objects, several 
people posted examples [3, 4] that broke the suggested 
optimization of eliding `opAddRef()`/`opRelease()` calls in 
certain situations.

A weakness of the same kind affects DIP25, too. The core of the 
problem is borrowing (ref return as in DIP25), combined with 
manual (albeit hidden) memory management. An example to 
illustrate:

     struct T {
         void doSomething();
     }
     struct S {
         RCArray!T array;
     }
     void main() {
         auto s = S(RCArray!T([T()])); // s.array's refcount is 
now 1
         foo(s, s.array[0]);           // pass by ref
     }
     void foo(ref S s, ref T T) {
         s.array = RCArray!T([]);      // drop the old s.array
         t.doSomething();              // oops, t is gone
     }

Any suggestions how to deal with this? As far as I can see, there 
are the following options:

1) Make borrowing (return ref) @system. This would defeat the 
purpose of DIP25.

2) Disallow (by convention) borrowing for refcounted objects. 
Again, this would make DIP25 pointless, and strictly speaking, 
anything that relies on convention cannot be @safe. And there's 
no guarantee that it doesn't affect other things besides RC.

3) Introduce a full linear type system. A _very_ large and 
invasive change, and probably cumbersome to work with.

4) Live with it. Accept that it's not possible to get the last 
bit of @safe-ty without extreme and unjustifiable costs. Make it 
@safe nevertheless, and formulate usage guides that people are 
expected to follow.

5) Make `RCArray` a special type whose purpose is known to the 
compiler, and implement complicated checks to verify @safe-ty. 
Again, kind of defeats the purpose, and adds complexity to the 
language and implementation.

6) Restrict borrowing to situations where it's @safe. Or better, 
allow it everywhere, but make it @system where necessary. I think 
problems can only happen at function boundaries (what happens 
inside a function can be checked statically), but I'd have to 
think about it more.

7) Anything else? Are there some small details (in whatever part 
of the language) that can be adjusted to get us additional 
guarantees?

Option 6) currently appears the most promising to me.

Comments?

[1] http://forum.dlang.org/thread/mcg8qq$1mbr$1@digitalmars.com
[2] http://wiki.dlang.org/DIP25
[4] 
http://forum.dlang.org/post/ilfwmeobprkcorpiqoui@forum.dlang.org
[5] http://forum.dlang.org/post/mcqk4s$6qb$1@digitalmars.com


More information about the Digitalmars-d mailing list