April 10, 2015
On 4/10/2015 2:20 PM, Martin Nowak wrote:
> On 04/10/2015 12:29 PM, Walter Bright wrote:
>>>
>>> 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.
>>
>> Or you could pass it by const ref (which is what Rust essentially does).
>
> Maybe I'm missing something, but this proposal seems to make `ref RCO`
> fairly useless, because it creates a copy anyhow.

Not if you read the copy elision section.


> Assigning a RefCounted is marked @system,

That's kind of throwing in the towel, isn't it?

> pass-by-ref is @safe.
> What's missing, you want to be able to use RefCounted in @safe code? Why
> not pass it by value then? That would pin the object and you could elide
> the additional inc/dec just like you propose to elide the temporary copies.
> It's more efficient to pass a smart pointer like RefCounted by-value anyhow.


April 10, 2015
On 4/10/2015 2:11 PM, Martin Nowak wrote:
> On 04/09/2015 01:10 AM, Walter Bright wrote:
>> http://wiki.dlang.org/DIP77
>
> In the first problem example:
>
>   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
>   }
>
> What do you do to pin s.array?
>
> auto tmp = s;
>
> or
>
> auto tmp = s.array;
>

The latter.
April 10, 2015
On Friday, 10 April 2015 at 21:20:32 UTC, Martin Nowak wrote:
> Assigning a RefCounted is marked @system, pass-by-ref is @safe.
> What's missing, you want to be able to use RefCounted in @safe code? Why
> not pass it by value then?

This actually sounds quite logical to me - passing an RC object by ref doesn't sound very safe to begin with.
April 10, 2015
On 2015-04-10 21:29:19 +0000, Walter Bright <newshound2@digitalmars.com> said:

> On 4/10/2015 2:11 PM, Martin Nowak wrote:
>> On 04/09/2015 01:10 AM, Walter Bright wrote:
>>> http://wiki.dlang.org/DIP77
>> 
>> In the first problem example:
>> 
>>   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
>>   }
>> 
>> What do you do to pin s.array?
>> 
>> auto tmp = s;
>> 
>> or
>> 
>> auto tmp = s.array;
>> 
> 
> The latter.

And how is it pinned in this case?

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

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca

April 10, 2015
On Friday, 10 April 2015 at 21:50:13 UTC, Michel Fortin wrote:
> On 2015-04-10 21:29:19 +0000, Walter Bright <newshound2@digitalmars.com> said:
>
>> On 4/10/2015 2:11 PM, Martin Nowak wrote:
>>> On 04/09/2015 01:10 AM, Walter Bright wrote:
>>>> http://wiki.dlang.org/DIP77
>>> 
>>> In the first problem example:
>>> 
>>>  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
>>>  }
>>> 
>>> What do you do to pin s.array?
>>> 
>>> auto tmp = s;
>>> 
>>> or
>>> 
>>> auto tmp = s.array;
>>> 
>> 
>> The latter.
>
> And how is it pinned in this case?
>
>  struct S {
>      private RCArray!T array;
>      ref T opIndex(int index) return { return array[index]; }
>      void clear() { s.array = RCArray!T([]); }
>  }
>  void main() {
>      auto s = S(RCArray!T([T()])); // s.array's refcount is now 1
>      foo(s, s[0]);           // pass by ref
>  }
>  void foo(ref S s, ref T t) {
>      s.clear();            // drop the old s.array
>      t.doSomething();              // oops, t is gone
>  }

AFAICT it would create a temporary copy of s.array, which would keep t valid.

> Nope. It'll scan at compile time the types reachable through the parameters. If any of those types are RCO's that have a type that matches a ref parameter, the
ref parameter's RCO will get copied.
April 10, 2015
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.
April 10, 2015
On 04/10/2015 11:29 PM, Walter Bright wrote:
> 
> The latter.

Can you update that part in the DIP, it wasn't clear that the temporary selectively pins RCO fields of a normal struct passed by ref.
April 10, 2015
On Friday, 10 April 2015 at 23:18:59 UTC, Martin Nowak wrote:
> On 04/10/2015 11:29 PM, Walter Bright wrote:
>> 
>> The latter.
>
> Can you update that part in the DIP, it wasn't clear that the temporary
> selectively pins RCO fields of a normal struct passed by ref.

If a struct has RCO fields, shouldn't it be an RCO itself, and as such be pinned ?

It sounds like this is implied in the DIP.
April 11, 2015
On 2015-04-10 23:22:17 +0000, "deadalnix" <deadalnix@gmail.com> said:

> On Friday, 10 April 2015 at 23:18:59 UTC, Martin Nowak wrote:
>> On 04/10/2015 11:29 PM, Walter Bright wrote:
>>> 
>>> The latter.
>> 
>> Can you update that part in the DIP, it wasn't clear that the temporary
>> selectively pins RCO fields of a normal struct passed by ref.
> 
> If a struct has RCO fields, shouldn't it be an RCO itself, and as such be pinned ?

Not necessarily. A @disabled postblit could make it no longer RCO (including a @disabled postblit in one of the fields).

> It sounds like this is implied in the DIP.

That's what I thought too. But when confronted to a case where that wouldn't work Walter said in this thread that the compiler would make a temporary of the fields. So I'm not too sure what to think anymore. The DIP should clarify what happens with @disabled postblit and RCO fields inside non-RCO structs.

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca

April 11, 2015
On 4/10/2015 2:50 PM, Michel Fortin wrote:
> And how is it pinned in this case?
>
>   struct S {
>       private RCArray!T array;
>       ref T opIndex(int index) return { return array[index]; }
>       void clear() { s.array = RCArray!T([]); }
>   }
>   void main() {
>       auto s = S(RCArray!T([T()])); // s.array's refcount is now 1
>       foo(s, s[0]);           // pass by ref

The s[0] is preceded by tmp=s; Because T is reachable from typeof(first argument s)

>   }
>   void foo(ref S s, ref T t) {
>       s.clear();            // drop the old s.array
>       t.doSomething();              // oops, t is gone
>   }
>