August 16, 2016
On 8/16/2016 6:01 PM, H. S. Teoh via Digitalmars-d-announce wrote:
> On Wed, Aug 17, 2016 at 01:01:05AM +0000, Chris Wright via Digitalmars-d-announce wrote:
>> On Tue, 16 Aug 2016 18:55:40 +0000, Dicebot wrote:
>>> You need to add one more level of indirection for things to start
>>> going complicated.
>>
>> Presumably scope is transitive, so things shouldn't get horribly
>> complex.
>
> I thought the DIP states the scope is *not* transitive?

It is not transitive.

August 17, 2016
On Wednesday, 17 August 2016 at 01:42:00 UTC, Walter Bright wrote:

>> Can you please clarify the current implementation `scope`, and what DIP1000
>> proposes to change with respect to the current implementation?
>
> It just adds to the existing compiler implementation of 'scope'. It has nothing to do with std.typecons.scoped.

Ok, but the deprecations page [1] gives this example...

class A
{
    int x;
    this(int x) { this.x = x; }
}

void main()
{
    A obj;
    {
        scope A a = new A(1);
        obj = a;
    }
    assert(obj.x == 1);  // fails, 'a' has been destroyed
}

... as a deprecated pattern, and corrected with ...

class A
{
    this(int x) { }
}
void main()
{
    auto a = std.typecons.scoped!A(1);
}

However, in DIP1000, the examples use the above deprecated pattern extensively.  So what's the story?  Does the deprecations page [1] need an update?

[1] http://dlang.org/deprecate.html#scope%20for%20allocating%20classes%20on%20the%20stack
August 17, 2016
On 17 Aug 2016 04:00, "Mike via Digitalmars-d-announce" < digitalmars-d-announce@puremagic.com> wrote:
>
> On Wednesday, 17 August 2016 at 01:42:00 UTC, Walter Bright wrote:
>
>>> Can you please clarify the current implementation `scope`, and what
DIP1000
>>> proposes to change with respect to the current implementation?
>>
>>
>> It just adds to the existing compiler implementation of 'scope'. It has
nothing to do with std.typecons.scoped.
>
>
> Ok, but the deprecations page [1] gives this example...
>
> class A
> {
>     int x;
>     this(int x) { this.x = x; }
> }
>
> void main()
> {
>     A obj;
>     {
>         scope A a = new A(1);
>         obj = a;
>     }
>     assert(obj.x == 1);  // fails, 'a' has been destroyed
> }
>
> ... as a deprecated pattern, and corrected with ...
>
> class A
> {
>     this(int x) { }
> }
> void main()
> {
>     auto a = std.typecons.scoped!A(1);
> }
>
> However, in DIP1000, the examples use the above deprecated pattern
extensively.  So what's the story?  Does the deprecations page [1] need an update?
>
> [1]
http://dlang.org/deprecate.html#scope%20for%20allocating%20classes%20on%20the%20stack

Basically DIP1000 makes it so that:
> void main()
> {
>     A obj;
>     {
>         scope A a = new A(1);
>         obj = a;
>     }
>     assert(obj.x == 1);  // fails, 'a' has been destroyed
> }

Will not compile.


August 17, 2016
On Wednesday, 17 August 2016 at 04:28:33 UTC, Rory McGuire wrote:

> Basically DIP1000 makes it so that:
>> void main()
>> {
>>     A obj;
>>     {
>>         scope A a = new A(1);
>>         obj = a;
>>     }
>>     assert(obj.x == 1);  // fails, 'a' has been destroyed
>> }
>
> Will not compile.

Ok, that makes sense. But then the feature illustrated on the deprecations page is wrong.  I think what has been deprecated is `scope` as a type modifier, not `scope` as a storage class, but the example on the deprecations page illustrates the `scope` storage class, not the type modifier.

I believe what the deprecations page intended to say was that this has been deprecated:
scope class A
{
    this(int x) { }
}

And DIP1000 finally implements the `scope` storage class properly:
void main()
{
    A obj;
    {
        scope A a = new A(1);
        obj = a;              // compile-time error.  Good!
    }
    assert(obj.x == 1);       // or is it usage that triggers the compile-time error?
}

Mike
August 17, 2016
On Wednesday, 17 August 2016 at 06:44:41 UTC, Mike wrote:
> On Wednesday, 17 August 2016 at 04:28:33 UTC, Rory McGuire wrote:
>
>> Basically DIP1000 makes it so that:
>>> void main()
>>> {
>>>     A obj;
>>>     {
>>>         scope A a = new A(1);
>>>         obj = a;
>>>     }
>>>     assert(obj.x == 1);  // fails, 'a' has been destroyed
>>> }
>>
>> Will not compile.
>
> Ok, that makes sense. But then the feature illustrated on the deprecations page is wrong.  I think what has been deprecated is `scope` as a type modifier, not `scope` as a storage class, but the example on the deprecations page illustrates the `scope` storage class, not the type modifier.
>
> I believe what the deprecations page intended to say was that this has been deprecated:
> scope class A
> {
>     this(int x) { }
> }
>
> And DIP1000 finally implements the `scope` storage class properly:
> void main()
> {
>     A obj;
>     {
>         scope A a = new A(1);
>         obj = a;              // compile-time error.  Good!
>     }
>     assert(obj.x == 1);       // or is it usage that triggers the compile-time error?
> }
>
> Mike

Or perhaps DIP1000 changes the current behavior of the `scope` storage class.

My understanding is that the `scope` storage class currently allocates a class on the stack (though its usage for this purpose is deprecated in favor of std.typecons.scoped).  If DIP1000 is implemented, it will change that behavior, so the allocation will instead be on the GC heap, but the compiler will do some flow-control analysis to prevent escaping references.  Is that right?

Mike
August 17, 2016
On Wednesday, 17 August 2016 at 07:04:26 UTC, Mike wrote:

>
> Or perhaps DIP1000 changes the current behavior of the `scope` storage class.
>
> My understanding is that the `scope` storage class currently allocates a class on the stack (though its usage for this purpose is deprecated in favor of std.typecons.scoped).  If DIP1000 is implemented, it will change that behavior, so the allocation will instead be on the GC heap, but the compiler will do some flow-control analysis to prevent escaping references.  Is that right?
>

I may have found my answer in the DIP, but there is some ambiguity:

"Currently, scope is ignored except that a new class use to initialize a scope variable allocates the class instance on the stack. Fortunately, this can work with this new proposal, with an optimization that recognizes that if a new class is unique, and assigned to a scope variable, then that instance can be placed on the stack."

"can be placed on the stack", or "will be placed on the stack"?  And only "if the new class is unique"?  I'm assuming unique mean a new instance with a reference count (for lack of a better word) no greater than 1.

Mike



August 17, 2016
On Wed, Aug 17, 2016 at 9:04 AM, Mike via Digitalmars-d-announce < digitalmars-d-announce@puremagic.com> wrote:
>
>
> Or perhaps DIP1000 changes the current behavior of the `scope` storage class.
>
> My understanding is that the `scope` storage class currently allocates a class on the stack (though its usage for this purpose is deprecated in favor of std.typecons.scoped).


Correct. I believe the reason for the deprecation was that it was too easy to use considering how easy it was to get it's usage wrong, and that a library implementation would be just as good, which would also lessen the number of reserved words D has, and make devs more likely to check the documentation for its caveats.


>   If DIP1000 is implemented, it will change that behavior, so the
> allocation will instead be on the GC heap, but the compiler will do some
> flow-control analysis to prevent escaping references.  Is that right?
>
> Mike
>

Not correct, the class would still be on the stack so we can have reference semantics during assignment etc, but the instance is on the stack so its faster and the function the code is inside can optionally be nogc.

DIP1000 will just make the compiler check that a stack instance does not escape its scope (though it doesn't cover all cases).

struct Astruct {} // - on stack by default
class Aclass  {} // - on heap by default
void main() {
    Astruct a = new Astruct; // override, now Astruct is on the heap
(because of "new")
    Aclass c = new Aclass; // on the heap as per-usual
    scope Aclass c1 = new Aclass; // override, now class is on the stack
(most obvious use: to make all references use the same instance)
}


August 17, 2016
On Wednesday, 17 August 2016 at 07:17:24 UTC, Rory McGuire wrote:
>
>>   If DIP1000 is implemented, it will change that behavior, so the
>> allocation will instead be on the GC heap, but the compiler will do some
>> flow-control analysis to prevent escaping references.  Is that right?
>>
>> Mike
>>
>
> Not correct, the class would still be on the stack so we can have reference semantics during assignment etc, but the instance is on the stack so its faster and the function the code is inside can optionally be nogc.
>
> DIP1000 will just make the compiler check that a stack instance does not escape its scope (though it doesn't cover all cases).
>
> struct Astruct {} // - on stack by default
> class Aclass  {} // - on heap by default
> void main() {
>     Astruct a = new Astruct; // override, now Astruct is on the heap
> (because of "new")
>     Aclass c = new Aclass; // on the heap as per-usual
>     scope Aclass c1 = new Aclass; // override, now class is on the stack
> (most obvious use: to make all references use the same instance)
> }

Got it!  Thank you!  But it still appears that what's illustrated on the deprecations page is not being deprecated.

Mike
August 17, 2016
On Wednesday, 17 August 2016 at 07:53:49 UTC, Mike wrote:
> Got it!  Thank you!  But it still appears that what's illustrated on the deprecations page is not being deprecated.
>
> Mike

I imagine that will change if/when DIP1000 is accepted.
August 17, 2016
On 08/17/2016 10:53 AM, Mike wrote:
> On Wednesday, 17 August 2016 at 07:17:24 UTC, Rory McGuire wrote:
>>
>>>   If DIP1000 is implemented, it will change that behavior, so the
>>> allocation will instead be on the GC heap, but the compiler will do some
>>> flow-control analysis to prevent escaping references.  Is that right?
>>>
>>> Mike
>>>
>>
>> Not correct, the class would still be on the stack so we can have reference semantics during assignment etc, but the instance is on the stack so its faster and the function the code is inside can optionally be nogc.
>>
>> DIP1000 will just make the compiler check that a stack instance does not escape its scope (though it doesn't cover all cases).
>>
>> struct Astruct {} // - on stack by default
>> class Aclass  {} // - on heap by default
>> void main() {
>>     Astruct a = new Astruct; // override, now Astruct is on the heap
>> (because of "new")
>>     Aclass c = new Aclass; // on the heap as per-usual
>>     scope Aclass c1 = new Aclass; // override, now class is on the stack
>> (most obvious use: to make all references use the same instance)
>> }
> 
> Got it!  Thank you!  But it still appears that what's illustrated on the deprecations page is not being deprecated.
> 
> Mike

Yes, it will have to be updated - but I didn't want to adjust it before DIP1000 spec is finalized. Rationale that was driving deprecation of scope storage class is becoming obsolete with DIP1000 implemented but not before.