www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Why is 'scope' so weak?

reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
If I've understood things correctly, by marking a delegate parameter with 
'scope' you tell the compiler not to create a true closure for the 
delegate.  Effectively you're saying "I promise not to escape this 
delegate, so you don't need to copy its context to the heap".

In brief, my question is:  Why doesn't the compiler enforce this 
promise?  In particular, why is 'scope' not a type constructor?

(Note that this is mostly a question out of curiosity, and not really a 
proposal for a new feature.  I imagine it has been discussed in the past 
and rejected for some reason.)

Considering that the compiler enforces proper use of pure, nothrow, 
const, and all those other things, it doesn't seem much harder to do the 
same with scope.

As an example, I really can't see a reason why obviously wrong code like 
this should be allowed:

    void delegate() globalDg;

    void foo(scope void delegate() dg)
    {
        globalDg = dg;
    }

Here's a slightly less obvious example, which also compiles successfully:

    void foo(void delegate() dg);  // Who knows what this does?

    void bar(scope void delegate() dg)
    {
        foo(dg);
    }

-Lars
Nov 23 2010
next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Tue, 23 Nov 2010 12:59:27 +0000, Lars T. Kyllingstad wrote:

 [...]

Here's a fun example, which compiles and runs without error. It may seem contrived, but it shows that all it takes is someone forgetting to remove 'scope' when they change the implementation of a function, and memory corruption ensues. void delegate() globalDg; void call(scope void delegate() dg) { dg(); // Don't tell anyone, but I'm saving this for later ;) globalDg = dg; } void foo() { int i; void izero() { i = 0; } call(&izero); assert (i == 0); // As expected } void bar() { int x = 123; // Simply calling some function cannot possibly // do anything to x... globalDg(); // ...or can it? assert (x == 0); } void main() { foo(); bar(); }
Nov 23 2010
prev sibling next sibling parent dsimcha <dsimcha yahoo.com> writes:
== Quote from Lars T. Kyllingstad (public kyllingen.NOSPAMnet)'s article
 Considering that the compiler enforces proper use of pure, nothrow,
 const, and all those other things, it doesn't seem much harder to do the
 same with scope.

I haven't thought through all the implications yet, but at first glance making scope a transitive type constructor that is only valid for local variables and function parameters, but not global or member variables, seems like an interesting idea. In the case of structs, I guess a member variable could be scope if and only if the struct is a local variable and the member variable inherits the scope attribute. In any case, member variables would never be directly taggable as scope, since structs could be heap-allocated. I guess the rule would be that non-scope can implicitly convert to scope (since something that lives on the heap can be safely used anywhere) but not the other way around?
Nov 23 2010
prev sibling next sibling parent reply "Robert Jacques" <sandford jhu.edu> writes:
On Tue, 23 Nov 2010 07:59:27 -0500, Lars T. Kyllingstad  
<public kyllingen.nospamnet> wrote:

 If I've understood things correctly, by marking a delegate parameter with
 'scope' you tell the compiler not to create a true closure for the
 delegate.  Effectively you're saying "I promise not to escape this
 delegate, so you don't need to copy its context to the heap".

 In brief, my question is:  Why doesn't the compiler enforce this
 promise?  In particular, why is 'scope' not a type constructor?

For scope to be a type constructor, D requires some form of ownership-types & local escape analysis. Just like mutable and immutable data needs const, I think stack/thread-local/shared data needs scope. (There is an old proposal on the wiki about the technical implementation, though it's badly worded) But my understanding is that all things ownership related are relegated to D3.
Nov 23 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/24/10 5:06 AM, Lars T. Kyllingstad wrote:
 On Tue, 23 Nov 2010 23:26:54 -0500, Robert Jacques wrote:

 On Tue, 23 Nov 2010 07:59:27 -0500, Lars T. Kyllingstad
 <public kyllingen.nospamnet>  wrote:

 If I've understood things correctly, by marking a delegate parameter
 with 'scope' you tell the compiler not to create a true closure for the
 delegate.  Effectively you're saying "I promise not to escape this
 delegate, so you don't need to copy its context to the heap".

 In brief, my question is:  Why doesn't the compiler enforce this
 promise?  In particular, why is 'scope' not a type constructor?

For scope to be a type constructor, D requires some form of ownership-types& local escape analysis. Just like mutable and immutable data needs const, I think stack/thread-local/shared data needs scope. (There is an old proposal on the wiki about the technical implementation, though it's badly worded) But my understanding is that all things ownership related are relegated to D3.

Well, I think something needs to be done about it in D2 as well, because right now 'scope' allows memory corruption to happen even in safe mode, as demonstrated by this slightly modified example:

This is a bug. Could you please file it as major? Andrei
Nov 24 2010
parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
On 24/11/2010 17:08, Lars T. Kyllingstad wrote:
 On Wed, 24 Nov 2010 10:34:10 -0600, Andrei Alexandrescu wrote:

 On 11/24/10 5:06 AM, Lars T. Kyllingstad wrote:
 On Tue, 23 Nov 2010 23:26:54 -0500, Robert Jacques wrote:

 On Tue, 23 Nov 2010 07:59:27 -0500, Lars T. Kyllingstad
 <public kyllingen.nospamnet>   wrote:

 If I've understood things correctly, by marking a delegate parameter
 with 'scope' you tell the compiler not to create a true closure for
 the delegate.  Effectively you're saying "I promise not to escape
 this delegate, so you don't need to copy its context to the heap".

 In brief, my question is:  Why doesn't the compiler enforce this
 promise?  In particular, why is 'scope' not a type constructor?

For scope to be a type constructor, D requires some form of ownership-types& local escape analysis. Just like mutable and immutable data needs const, I think stack/thread-local/shared data needs scope. (There is an old proposal on the wiki about the technical implementation, though it's badly worded) But my understanding is that all things ownership related are relegated to D3.

Well, I think something needs to be done about it in D2 as well, because right now 'scope' allows memory corruption to happen even in safe mode, as demonstrated by this slightly modified example:

This is a bug. Could you please file it as major?

http://d.puremagic.com/issues/show_bug.cgi?id=5270 I'm curious to see what the solution to this will be. -Lars

Indeed, is the bug that one cannot use scope delegates in safe code? -- Bruno Medeiros - Software Engineer
Dec 07 2010
prev sibling next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Tue, 23 Nov 2010 23:26:54 -0500, Robert Jacques wrote:

 On Tue, 23 Nov 2010 07:59:27 -0500, Lars T. Kyllingstad
 <public kyllingen.nospamnet> wrote:
 
 If I've understood things correctly, by marking a delegate parameter
 with 'scope' you tell the compiler not to create a true closure for the
 delegate.  Effectively you're saying "I promise not to escape this
 delegate, so you don't need to copy its context to the heap".

 In brief, my question is:  Why doesn't the compiler enforce this
 promise?  In particular, why is 'scope' not a type constructor?

For scope to be a type constructor, D requires some form of ownership-types & local escape analysis. Just like mutable and immutable data needs const, I think stack/thread-local/shared data needs scope. (There is an old proposal on the wiki about the technical implementation, though it's badly worded) But my understanding is that all things ownership related are relegated to D3.

Well, I think something needs to be done about it in D2 as well, because right now 'scope' allows memory corruption to happen even in safe mode, as demonstrated by this slightly modified example: // The example I showed earlier, now with safe annotations. safe: void delegate() globalDg; void call(scope void delegate() safe dg) { dg(); // Don't tell anyone, but I'm saving this for later ;) globalDg = dg; } void foo() { int i; void izero() { i = 0; } call(&izero); assert (i == 0); } void bar() { int x = 123; // Simply calling some function cannot possibly // do anything to x... globalDg(); // ...or can it? assert (x == 0); } void main() { foo(); bar(); }
Nov 24 2010
prev sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Wed, 24 Nov 2010 10:34:10 -0600, Andrei Alexandrescu wrote:

 On 11/24/10 5:06 AM, Lars T. Kyllingstad wrote:
 On Tue, 23 Nov 2010 23:26:54 -0500, Robert Jacques wrote:

 On Tue, 23 Nov 2010 07:59:27 -0500, Lars T. Kyllingstad
 <public kyllingen.nospamnet>  wrote:

 If I've understood things correctly, by marking a delegate parameter
 with 'scope' you tell the compiler not to create a true closure for
 the delegate.  Effectively you're saying "I promise not to escape
 this delegate, so you don't need to copy its context to the heap".

 In brief, my question is:  Why doesn't the compiler enforce this
 promise?  In particular, why is 'scope' not a type constructor?

For scope to be a type constructor, D requires some form of ownership-types& local escape analysis. Just like mutable and immutable data needs const, I think stack/thread-local/shared data needs scope. (There is an old proposal on the wiki about the technical implementation, though it's badly worded) But my understanding is that all things ownership related are relegated to D3.

Well, I think something needs to be done about it in D2 as well, because right now 'scope' allows memory corruption to happen even in safe mode, as demonstrated by this slightly modified example:

This is a bug. Could you please file it as major?

http://d.puremagic.com/issues/show_bug.cgi?id=5270 I'm curious to see what the solution to this will be. -Lars
Nov 24 2010