D2 Multithreading Architecture

Robert Jacques sandford at jhu.edu
Wed Apr 29 08:34:23 PDT 2009


On Wed, 29 Apr 2009 04:26:55 -0400, Denis Koroskin <2korden at gmail.com>  
wrote:
> On Tue, 28 Apr 2009 23:06:32 +0400, Robert Jacques <sandford at jhu.edu>
>> ┌───────┬──────────────┬────────────────────┬─────────────┐
>> │ scope │ Common Super │ Unknown Allocation │ Transitive† │
>> └───────┴──────────────┴────────────────────┴─────────────┘
>> Use of the scope keyword for the common ownership-type is based upon  
>> Walter’s original escape analysis blog. However, this design is based  
>> upon using the type system restrictions as opposed to full escape  
>> analysis to prevent object escape. Full escape analysis would alleviate  
>> the restrictions in rule 6.
>> Basic Rules:
>> 1) Refers to scope definitions inside a function body.
>> 2) May only be assigned at declaration
>>         scope Node!(int) n;
>>         n.next = new Node!(int)(); // Error: Possible escape
>>         n = n.next;                // Error: see relaxation of this  
>> rule below
>
> What's Node? Is it a class or a struct?

Opps. Class. I've updated the wiki4D page with
scope Node!(int) n = mySharedNode;

> I believe you should have put Node's definition, first, and explained  
> and implicit ctor call, if one takes place.

Okay.

>> 3) Applies to references taken from scope types
>>         scope int* value = &(n.value);
>
> So, scope T and scope T* have different meaning?
>
> scope T means that T is constructed on stack, but scope T* is  
> essentially "a pointer to scope variable". If that's the case, it is  
> *very* confusing, because one could expect scope T to be the same no  
> matter T is a class, a struct or a primitive type like int or ptr.

No, your confusion stems from Walter's choice to reuse the scope keyword,  
yet again.
Logically,
scope T  -> scope(T)
scope T* -> scope(T*)
As scope is transitive.

> It would be better to write
>
> scope(int)* value = &(n.value);
>
> Now it's more clear that value is a pointer to a data of type int which  
> is stored on stack. I believe that's what intended in your example.

Though this is also correct. (Wiki code example updated)

>> 4) Implicit conversion is always fully transitive.
>>         Foo[] y;
>>         scope Foo[]  x = y;
>
> I don't understand what this example does.
>> 5) Mixed implicit conversion is illegal.
>>         scope(Foo)[] z = y; // Error: cannot implicitly convert...

Rule 4 and 5 have to do with the ways arrays can create loopholes in the  
type system (Bug 2095, http://d.puremagic.com/issues/show_bug.cgi?id=2095)
Adding a link in the wiki.

>> 4) Objects and structs use the local interface
>>         f.push(5);                      // Error: push is not part of  
>> the scope interface
>>         temp.push(5);                   // Okay, push is part of the  
>> local interface
>>
>
> I don't understand this example. What's the difference between temp and  
> f? They all said to be the same (see example 1).
> What's a difinition of push, anyway? *Please*, provide class difinition,  
> first.

Opps. My example is completly wrong. *Sigh* How's this.

auto sf = new auto(Stack!(Foo))();  // declared as class Stack(T) {},  
stack interface defaults
auto f1 = new Foo();
auto f2 = new auto(Foo)();
sf.push(f1);                        // Okay,  push(local Foo) is defined
sf.push(f2);                        // Error: push(stack Foo) is is not  
defined, use a scope class declaration instead

And I need to work on clearer examples...

>> Note that this catches all of Walter’s examples from the Escape  
>> Analysis blog via rule 3:
>>         int* foo()
>>         {
>>             int x = 3;
>>             return &x;                  // Error: can not convert type  
>> auto(int)* to int*
>>         }
>>
>>         int* bar(int* p) { return p; }
>>         int* foo()
>>         {
>>             int x = 3;
>>             return bar(&x);             // Error: ditto
>>         }
>>
>>         void abc(int x, int** p) { *p = &x; } // Error: ditto
>>
>
> I don't see *any* difference between scope and stack variables. Besides,  
> both using the same keyword, scope, and essentially are the same. It's  
> very confusing because I got no idea about the difference between them,  
> aside from scope object being created automagically and stack object  
> need to be constructed explicitly:
>
> scope Node!(int) n; // scope
> scope Foo foo = new Foo(); // stack
>
> All I can say, wtf?

Honestly, I seriously though of using final instead of scope to avoid just  
this confusion. But I decided to follow Walter's choice. (Besides it's  
more intuitive).

scope Foo foo = new Foo();        // Foo is a of type scope and has been  
allocated on the stack. (see rule 1)
auto  Foo f2  = new scope(Foo)(); // Foo is a of type stack and has been  
allocated on the stack. (see rule 1)

I think scope Foo foo = new Foo(); should be probably be deprecated.  
(which I hinted at in the class definition section)

> The proposal sound reasonable, but it's hard to follow. I really can't  
> comment on it because I didn't fully understand it.
>
> Many of my coworkers are preparing for an upcoming Game Developers  
> Conference (КРИ, Russia) and we listen to the their talks everyday, spot  
> errors, make some suggestions etc. And almost everyone does the same  
> mistake: they explain solution without explaining a problem. It is very  
> important but *really* hard to understand *why* you do something when  
> you don't know what's a problem is.
>
> I believe your proposal suffers from it, too. For example, when reading  
> an introduction, I see this:
>
>> ┌──────────────┐
>> │ Overview     │
>> ├──────────────┼─────────────────┬─────────────┬──────────────┐
>> │ Hierarchy    │ Description     │ Ownership   │ Transitivity │
>> ├──────────────┼─────────────────┼─────────────┼──────────────┤
>> │ scope        │ super-interface │ unknown     │ deep†        │
>> │  ││└─stack   │ current scope   │ stack       │ implicit     │
>> │  │└──local   │ object default  │ local-heap  │ deep†        │
>> │  ├───shared  │ thread safe     │ shared-heap │ deep†        │
>> │  └───mobile  │ unique objects  │ shared-heap │ shallow      │
>> └──────────────┴─────────────────┴─────────────┴──────────────┘
>
> You tell that you introduce 5 different qualifiers but you don't explain  
> why are they needed. Why not 4, not 3? What problem each of them solve?  
> All I can do is guess and be proven wrong, that's the most frustrating.
> Next, you tell about issues:
>
>> •scope(T) in a function body conflicts with scope guard statements.  
>> This is a general problem with Walter’s choice of using the scope  
>> keyword for this concept. A clean solution is to mandate the use of {}  
>> in scope guard statements. Others include using an alternative  
>> keyword(auto, final, scope!(exit)), let the ambiguity stand, add a  
>> keyword, etc.
>
> Great! You never told that "scope" keyword is used by your proposal.  
> Without showing any line of code, it's absolutely worthless to mention  
> keyword conflict. Issues belongs to "pros and cons" section at the end  
> of your proposal, just before a conclusion.
>
> I also didn't understand a difference between scope and stack - that's  
> pretty much all you explained! You gave no example of shared or mobile  
> object, how they are used, how ownership passing occurs etc. I expected  
> to see a rationale of these qualifiers, but there is no one.
>
> cents += 2;
>

Thanks a lot for the comments. They a really appreciated. I see I need to  
go back and do some rewriting.




More information about the Digitalmars-d mailing list