DIP77 - Fix unsafe RC pass by 'ref'

w0rp via Digitalmars-d digitalmars-d at puremagic.com
Sat Apr 11 03:13:59 PDT 2015


On Saturday, 11 April 2015 at 09:28:46 UTC, Marc Schütz wrote:
> On Friday, 10 April 2015 at 23:12:55 UTC, deadalnix wrote:
>> On Friday, 10 April 2015 at 10:02:01 UTC, Martin Nowak wrote:
>>> On Wednesday, 8 April 2015 at 23:11:08 UTC, Walter Bright 
>>> wrote:
>>>> http://wiki.dlang.org/DIP77
>>>
>>> So someone passes an RCO via ref to avoid the inc/dec, and 
>>> because that imposes safety issues we turn it into some sort 
>>> of pass by value under the hood, defeating the purpose, and 
>>> provide an opt-out via @system opAssign.
>>>
>>> Wouldn't it more straightforward to make pass-by-ref unsafe 
>>> (@system) for RCOs?
>>>
>>> Then the only thing missing to make this equally powerful, 
>>> would be an optimization opportunity for the compiler to 
>>> elide copies of pass-by-value RCOs, e.g. it could avoid 
>>> calling the postblit when the function retains the refcount.
>>
>> Only the first pass by ref create a copy. You can then pass 
>> the ref down all you want without copy.
>>
>> That is an acceptable cost IMO.
>
> It's not acceptable that it happens behind the user's back. 
> Costly operations must be explicit.

If we somehow know for a fact that the object really is a 
reference counted object, then the cost should be acceptable. 
Running the postblit will consist of incrementing a reference 
count and nothing else. There's no other way I can think of that 
permits passing the object safely.

I think the one thing in the DIP I'm not sure of is the 
definition of what is a reference counted object. Say you write 
this.

struct Widget {
     byte* data;
     size_t length;

     @trusted
     opAssign(ref const(Widget) other) {
         length = other.length;

         data = malloc(length);
         memcpy(cast(void*) data, cast(void*) other.data, length);
     }

     @trusted
     this(this) {
         auto oldData = data;

         data = malloc(length);
         memcpy(cast(void*) data, cast(void*) oldData, length);
     }

     @trusted
     ~this() {
         free(data);
     }
}

Why would you want to do this? Who knows. According to DIP77 the 
object above is defined to be a reference counted object, when it 
isn't. If we're rejecting the C++ answer of "don't write code 
that way," then the same rejection should apply here. We need to 
be able to say with 100% certainty that we are dealing with a 
reference counted object, or at least an object where we know the 
postblit is so trivial the cost of calling it will be small.


More information about the Digitalmars-d mailing list