December 04, 2014
On 12/4/2014 6:58 AM, Steven Schveighoffer wrote:
> This doesn't seem right. For GC data, the GC owns the data, that is true. But
> for Ref-counted data, there is more than one owner, and only when all the owners
> disown the data can it be destroyed.
>
> I think there is a disconnect here, you can't say *nobody* owns the data, and if
> you say one variable owns the data, which one is it?

The owner of the refcounted data is the refcounting wrapper - and the wrapper decides when to destroy the payload.

(For GC, the "wrapper" is the GC system, which decides to destroy the payload when there are no longer references to it. Just like a ref counting system.)

December 04, 2014
On 12/4/2014 4:55 AM, bearophile wrote:
> I am not expert in such things, but here are few comments and questions.
>
>> Errors for scope violations are only reported in @safe code.
>
> This seems acceptable only if the compiler switch "-scope" implies functions to
> be @safe by default and @system on request, because currently lot of D
> programmers don't apply annotations like @safe to their D code. Opt-in safety
> doesn't work well (and in D we still have the problems caused by null pointers
> and references).

Safety by default is outside of the sco[pe (!) of this discussion. Also, you can merely put:

    @safe:

at the beginning of a module and it is now all safe.

> Also consider an annotation like "!scope" or "@escape" for the opposite purpose.

That's part of a more general issue of negation of attributes.


>> Delegates currently defensively allocate closures with the GC. Few actually
>> escape, and with scope only those that actually escape need to have the
>> closures allocated.<
>
> So there's no need for extra annotations to make delegates @nogc in most cases?

Marking delegates as @nogc does not affect the closure, as the closure is allocated when the enclosing function is entered.



> Regarding array literals, some people proposed a syntax for fixed-size arrays to
> avoid heap-allocations (the "s" after the array literal):
>
> void foo(int[2]) {}
> void bar(int[]) {}
> void main() @nogc {
>      foo([1, 2]s);
>      bar([1, 2]s);
> }
>
>
> Is DIP69 able to infer those arrays can be both stack-allocated? Is the "s"
> annotations still useful?

It's an idea worth exploring.


> Regarding the benefits, is escape analysis going to be used to allocate
> _automatically_ some small dynamic arrays and classes/structs on the stack
> instead of heap?

This is an optimization opportunity that scope enables.


> And is escape analysis going to automatically give hints to the GC to deallocate
> faster GC-allocated memory that doesn't escape?
>
> void foo() {
>      // Both dynamic arrays don't escape foo
>
>      // Automatically stack allocated.
>      auto a = new int[3];
>
>      // Heap-allocated but deterministically
>      // deleted at the end of foo scope.
>      auto b = new int[10_000];
> }

Another optimization opportunity.

December 04, 2014
On 12/4/2014 4:03 AM, Martin Nowak wrote:
> On Thursday, 4 December 2014 at 09:25:11 UTC, Walter Bright wrote:
>> http://wiki.dlang.org/DIP69
>>
> Great stuff.
>
> Will this be possible, it's a fairly important use-case.
>
> scope ref T setVal(scope ref T t)
> {
>      t.val = 12;
>      return t;
> }

Yes, it would be written:

  scope ref T setVal(ref T t)
  {
     t.val = 12;
     return t;
  }


> Another question, how would a reference counted pointer take advantage of scope,
> i.e. avoid the increment/decrement when being passed to a function?
> One solution would be to add a function that returns a scoped reference to the
> underlying value.
>      struct RefCounted(T)
>      {
>          scope ref T borrow() { return *p; }
>      }
> Will it be possible to deduce, that the lifetime of that scoped value is tied to
> the smart pointer?

  struct RefCounted(T)
  {
    T t;
    scope ref T borrow() { return t; }
    alias this t;
  }

This enables RefCounted!T to be implicitly converted to a T, but with a scoped result. This is a critical feature, one I spent a lot of time thinking about, and hope it's right :-)

December 04, 2014
On 12/4/2014 4:56 AM, Kagamin wrote:
> On Thursday, 4 December 2014 at 09:25:11 UTC, Walter Bright wrote:
>> http://wiki.dlang.org/DIP69
>
> How inout fits the picture? It has some scope semantics too.

s/inout/ref/


> Section about expressions suggests you will tack scoping carefully, but then why
> would you need return by ref tricks, which don't rely on scope tracking and
> hence look hackable?

Couldn't think of another way.
December 04, 2014
On 12/4/2014 7:04 AM, Steven Schveighoffer wrote:
> "Scope affects:
>
>      local variables allocated on the stack"
>
> ...
>
> "scope int i;       // scope is ignored because integers are not references and
> so are not views"
>
> I think I understand what you are trying to say -- the (big S) Scope of a local
> variable cannot escape, but it serves no purpose to declare a local int as
> (keyword) scope, since it's not going to be assigned any references.
>
> But it reads contradictory.

If you think that is contradictory, you should have read the earlier drafts :-)

Basically, I had to get straight in my head the difference between the scope of the variable and the scope of its payload.

The keyword 'scope' only affects the payload.

December 04, 2014
On 12/4/2014 7:25 AM, Steven Schveighoffer wrote:
> int* bar(scope int*);
> scope int* foo();
>
> bar(foo());           // Ok, lifetime(foo()) > lifetime(bar())
>
> I'm trying to understand how foo can be implemented in any case. It has no scope
> ints to return, so where does it get the int from?

Could be from a global variable. Or a new'd value.


> I don't see where the proposal defines what exactly can be returned via scope.

The scope return value does not affect what can be returned. It affects how that return value can be used. I.e. the return value cannot be used in such a way that it escapes the lifetime of the expression.


> Another thing I saw early on:
>
> void abc() {
>      scope int* a;
>      int* b;
>      scope ref int* c = a;  // Error, rule 5
>      scope ref int* d = b;  // Ok
>      int* i = a;            // Ok, scope is inferred for i
>      global_ptr = d;        // Error, lifetime(d) < lifetime(global_ptr)
>      global_ptr = i;        // Error, lifetime(i) < lifetime(global_ptr)
>      int* j;                // Ok, scope is inferred for i
>      global_ptr = j;        // Ok, j is not scope
> }
>
> Does this mean ref can now be applied to a variable?

    scope ref int p = x;

is the same meaning as:

    foo(scope ref int p);
    foo(x);

as far as what scope ref means. I found it convenient to use scope ref local variables to describe semantics. Whether we want to actually enable their usage hinges on if there's a point to it. Technically, it should work.


> I'm not sure what the difference between scope ref and scope is. is d defined as
> a reference to b, or is d defined as a new variable that is initialized to what
> b points at (a la C++ &) ?

Scope refers to the payload. A scope ref is applying scope to the implied ref pointer. ref works like C++ &.

December 04, 2014
On 12/4/2014 11:41 AM, H. S. Teoh via Digitalmars-d wrote:
> Can we pretty please use the term "type qualifier" instead of "type
> constructor"? ;-)

I think "type constructor" is the more pedantically correct term, but you'll have to ask Andrei :-)


> 1) Why are scope violations only reported for @safe code?? IMO this
> greatly limits the usefulness of this DIP.  If I mark something as
> scope, I'd expect it should be enforced by the compiler regardless of
> @safe annotations, otherwise what's the point??

Because there are inevitably cases where you'll need to wrap unsafe code with a safe interface. By screwing this down too tightly for @system code, you'll force people to use really ugly workarounds.


> Currently, due to the incompleteness of @safe, it's difficult to use
> @safe annotations everywhere I'd like to (e.g. I need to use some
> un-@safe Phobos functions that really ought to be @safe, but aren't due
> to various reasons, like compiler limitations, etc.). This greatly
> limits the usefulness of this DIP, if scope is only enforced in @safe
> code!

Are there bug reports on this?


> 2) Is there a way to detect if something is marked as scope?

Using __traits(compiles,...) ought to work.

> If not, how
> does this proposal actually enable ref-counted types? (I'm assuming a
> library ref-counting type here; or are we expecting further compiler
> enhancements for ref counting?)

The ref counting would be done by a wrapper, which implicitly converts to the wrappee by exposing a scope ref.


> 3) What does scope mean for delegate parameters? To what does the scope
> apply, the delegate itself, its body, or its return value, or ...?
>
> 	struct S {
> 		void opApply(scope void delegate(ref int) loopBody) {
> 			...
> 			// what restrictions (might) apply here w.r.t.
> 			// how loopBody can be called?
> 		}
> 	}

Hmmm, looks like a problem I didn't think of. darnit!


> And what would be the effect on the caller's side?
>
> 	S s;
> 	foreach (i; s) {
> 		// what restrictions (might) apply here?
> 	}

i would get its scope inferred as necessary, so restrictions would apply as they would to a 'scope i'.


> 4) Under "Expressions", how does scope interact with overloaded
> operators? Do the same rules apply to expressions that use overloaded
> operators as they apply to built-in operators, or do they apply as
> though the overloaded operators were written out in function-call
> syntax?  What happens if some overloaded operators take a mix of scope
> and non-scope parameters?

Overloaded operators are treated like calls to the functions that back them.


> Finally, the following isn't directly related to this DIP, since scope
> is intended to solve this problem, but I thought I should bring it up.
> :-) In the section "escaping via return", 5 points are listed as
> sufficient for detecting the "return func(t);" case. The following
> section "scope ref" states that these 5 points are "correct" (in
> implementing escaping reference detection). However, isn't the following
> a loophole?
>
> 	struct S {
> 		int x;
> 	}
> 	ref int func(ref S s) {
> 		return s.x;
> 	}
> 	ref T foo() {
> 		S s;
> 		return func(s); // escaping reference
> 	}
>
> Since S cannot implicitly convert to int, it would appear that this
> circumvents escaping reference detection.

No, because under this proposal, s.x is treated as if it were just s as far a scope rules are concerned.

> (In fact, dmd happily accepts
> this code, even if everything is annotated with @safe.)

I know, the current escape detection is quite inadequate - hence this proposal.

> Note that the
> escaping reference to x can be arbitrarily deeply nested inside S, so
> it's non-trivial to decide whether there's no possibility for references
> to (parts of) S to leak from func().

This proposal should lock that down.

December 04, 2014
On 12/4/2014 10:45 AM, H. S. Teoh via Digitalmars-d wrote:
> However, AFAIK, template *classes* trigger attribute inference on its
> (non-template) member functions, so this would be problematic:
>
> 	class Base(T) {
> 		T data;
> 		void method(ref T); // inferred to be scope
> 	}
>
> 	class Derived : Base!int {
> 		override void method(ref T); // oops, cannot override
> 	}

I agree, it's a good point. Scope inference cannot be done for virtual functions. I amended the DIP.

December 04, 2014
On 12/4/14 3:41 PM, Walter Bright wrote:
> On 12/4/2014 4:03 AM, Martin Nowak wrote:
>> Will it be possible to deduce, that the lifetime of that scoped value
>> is tied to
>> the smart pointer?
>
>    struct RefCounted(T)
>    {
>      T t;
>      scope ref T borrow() { return t; }
>      alias this t;
>    }
>
> This enables RefCounted!T to be implicitly converted to a T, but with a
> scoped result. This is a critical feature, one I spent a lot of time
> thinking about, and hope it's right :-)

Hm... did you mean `alias this borrow`?

-Steve


December 04, 2014
On Thu, Dec 04, 2014 at 12:41:58PM -0800, Walter Bright via Digitalmars-d wrote: [...]
>   struct RefCounted(T)
>   {
>     T t;
>     scope ref T borrow() { return t; }
>     alias this t;
>   }
> 
> This enables RefCounted!T to be implicitly converted to a T, but with a scoped result. This is a critical feature, one I spent a lot of time thinking about, and hope it's right :-)

Hold on, how does this convert to T with a scoped result? Or did you mean:

	...
	@property scope ref T borrow() { ... }
	alias borrow this;

?


T

-- 
Let's call it an accidental feature. -- Larry Wall