May 13, 2014
On 5/13/2014 10:09 AM, Steven Schveighoffer wrote:
> Yes, the difference here is that scope is a storage class, and only affects the
> "head", whereas borrowed would have to be transitive.

Are you sure it would have to be transitive?

May 13, 2014
On Tuesday, 13 May 2014 at 17:41:23 UTC, Walter Bright wrote:
> On 5/13/2014 6:36 AM, Dicebot wrote:
>> Main problem about making `ref` borrowed pointer is that you will need to
>> prohibit storing it in function transitively. This will need to become invalid
>> code:
>>
>> struct A
>> {
>>     int* ptr;
>> }
>>
>> int* gptr;
>>
>> void foo(ref A a)
>> {
>>     gptr = a.ptr; // error, can't leak borrowed a.ptr into global context
>> }
>
> The lifetime of &a is not at all the same as the lifetime of a.ptr, those are independent pointers. I.e. ref is not transitive (unlike const which is transitive).

It has to be transitive to be useful as borrowed pointer. Consider this example:

{
    scope A a; // has some internally managed resources
    foo(a);
}

It is not safe to destruct a in the end of the scope here because foo may have stored references to a owned resources. But if foo signature is `foo(scope ref A a)` then compiler can statically verify that it is safe which is the very point of borrowing guarantees. It must be transitive to guarantee anything of course.
May 13, 2014
On Tue, 13 May 2014 13:51:21 -0400, Walter Bright <newshound2@digitalmars.com> wrote:

> On 5/13/2014 10:09 AM, Steven Schveighoffer wrote:
>> Yes, the difference here is that scope is a storage class, and only affects the
>> "head", whereas borrowed would have to be transitive.
>
> Are you sure it would have to be transitive?

I'm not certain I understand the concept correctly, but from Dicebot's code example, it is transitive.

I defer to the experts. Just trying to help explain the point he was making (and clearly doing a poor job).

-Steve
May 13, 2014
On 5/13/2014 11:21 AM, Steven Schveighoffer wrote:
> I'm not certain I understand the concept correctly, but from Dicebot's code
> example, it is transitive.

I know Dicebot's example assumes a transitivity property, but I question that assumption.

In my cursory reading of Rust documentation, it wasn't clear to me if it was transitive or not.
May 13, 2014
On 5/13/2014 10:52 AM, Dicebot wrote:
> It has to be transitive to be useful as borrowed pointer. Consider this example:
>
> {
>      scope A a; // has some internally managed resources
>      foo(a);
> }
>
> It is not safe to destruct a in the end of the scope here because foo may have
> stored references to a owned resources. But if foo signature is `foo(scope ref A
> a)` then compiler can statically verify that it is safe which is the very point
> of borrowing guarantees. It must be transitive to guarantee anything of course.

If those internal resources of A are marked as refcounted, then transitivity is not necessary. Consider also that a struct A can completely control any escaping references - transitive borrowing is not necessary.
May 13, 2014
On Tuesday, 13 May 2014 at 18:48:14 UTC, Walter Bright wrote:
> On 5/13/2014 10:52 AM, Dicebot wrote:
>> It has to be transitive to be useful as borrowed pointer. Consider this example:
>>
>> {
>>     scope A a; // has some internally managed resources
>>     foo(a);
>> }
>>
>> It is not safe to destruct a in the end of the scope here because foo may have
>> stored references to a owned resources. But if foo signature is `foo(scope ref A
>> a)` then compiler can statically verify that it is safe which is the very point
>> of borrowing guarantees. It must be transitive to guarantee anything of course.
>
> If those internal resources of A are marked as refcounted, then transitivity is not necessary. Consider also that a struct A can completely control any escaping references - transitive borrowing is not necessary.

No, it still can be necessary. `scope` can greatly help not only with resource releasing, it is also missing tool to safely cast from shared. Locking shared variable can return same variable casted to scope qualifier which will guarantee  that no reference has been stored to shared object by the time lock is released.

And "if those are marked as refcounted" as assumption is no better than "if those are owned by GC" ;)

Also A can only control escaping of any internal references only by completely prohibiting access to it which is not good. You have no means to say "feel free to use this reference as long as you don't keep it outside of current scope". And you effectively say "make all your array members private to keep borrowing guarantees".

Rust situation is quite different here because all their safe pointers have ownership/lifetime annotation. D doesn't and thus imaginary scope/borrowed rules need to assume worst case scenarios (which is still good enough for many cases).
May 13, 2014
On 2014-05-13 19:52, Dicebot wrote:

> It has to be transitive to be useful as borrowed pointer. Consider this
> example:
>
> {
>      scope A a; // has some internally managed resources
>      foo(a);
> }
>
> It is not safe to destruct a in the end of the scope here because foo
> may have stored references to a owned resources. But if foo signature is
> `foo(scope ref A a)` then compiler can statically verify that it is safe
> which is the very point of borrowing guarantees. It must be transitive
> to guarantee anything of course.

What is "scope ref" supposed to do in this example, compared to just "scope"?

-- 
/Jacob Carlborg
May 13, 2014
On 5/13/2014 12:06 PM, Dicebot wrote:
> No, it still can be necessary. `scope` can greatly help not only with resource
> releasing, it is also missing tool to safely cast from shared. Locking shared
> variable can return same variable casted to scope qualifier which will
> guarantee  that no reference has been stored to shared object by the time lock
> is released.

I believe that is the role of `unique`. DIP69 addresses making unique pointers in D, and there have been several PR's implementing aspects of it.


> And "if those are marked as refcounted" as assumption is no better than "if
> those are owned by GC" ;)

I think that an object that wants to completely own its resources must properly encapsulate and restrict unsafe access to them itself.


> Also A can only control escaping of any internal references only by completely
> prohibiting access to it which is not good. You have no means to say "feel free
> to use this reference as long as you don't keep it outside of current scope".
> And you effectively say "make all your array members private to keep borrowing
> guarantees".

You can by only returning ref's.

May 13, 2014
On 5/13/2014 1:46 PM, Walter Bright wrote:
> I believe that is the role of `unique`. DIP69 addresses making unique pointers
> in D, and there have been several PR's implementing aspects of it.

Argh, DIP29:

http://wiki.dlang.org/DIP29
May 14, 2014
On Tuesday, 13 May 2014 at 17:44:02 UTC, Walter Bright wrote:
> On 5/13/2014 6:50 AM, Dicebot wrote:
>> Walter's initial post implies that he wanted to re-used `ref` for borrowed
>> pointer (which would mean same semantics as `scope` parameter qualifier)
>
> 'ref' already is to much extent, for example:
>
>   @safe int foo(ref int x) {
>     auto a = &x;
>     return 3;
>   }
>
> dmd foo -c
> foo.d(4): Error: cannot take address of parameter x in @safe function foo

This has nothing to do with `ref`. If you remove the `ref` you get the exact same error.