www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - "The last feature": scope structs

reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Following work on typechecking synchronized methods, Walter and I were 
discussing about managing escaping references to objects that wouldn't 
actually agree to escaping. The problem is that today a value has no 
idea that its address is being taken, so it has no saying in that.

To compensate for that, my idea was to allow  disable on opUnary!"&". 
Walter suggested allowing "scope" as a property of a struct:

scope struct Transitory
{
     ...
}

A scope struct cannot have its address taken. You can take addresses of 
its members (access permitting), but you can't take the address of any 
other struct that has at least one scope struct as a direct member. For 
example:

struct A
{
     int x;
     Transitory tr;
}

A will also be scope. So scope has this funny way of propagating 
outwards, as opposed to qualifiers, which propagate inwards.

This is as much as we have in terms of a design right now, so definitely 
it stands some more fleshing out. If gotten right, scope should allow 
defining a number of useful idioms, such as pass-down values, 
unique/lent objects, and the such.

Working against escapes has long been a problem, and with scope we're 
hoping to strike a balance between useful and simple.

Please share any thoughts you might have.


Andrei
Feb 07 2010
next sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Andrei Alexandrescu wrote:
 Following work on typechecking synchronized methods, Walter and I were 
 discussing about managing escaping references to objects that wouldn't 
 actually agree to escaping. The problem is that today a value has no 
 idea that its address is being taken, so it has no saying in that.
 
 To compensate for that, my idea was to allow  disable on opUnary!"&". 
 Walter suggested allowing "scope" as a property of a struct:
 
 scope struct Transitory
 {
     ...
 }
 
 A scope struct cannot have its address taken. You can take addresses of 
 its members (access permitting), but you can't take the address of any 
 other struct that has at least one scope struct as a direct member. For 
 example:
 
 struct A
 {
     int x;
     Transitory tr;
 }
 
 A will also be scope. So scope has this funny way of propagating 
 outwards, as opposed to qualifiers, which propagate inwards.

Though the feature seems useful, I worry about the asymmetry with scope classes. I think it will be very confusing to new D programmers that a scope class and a scope struct have very little to do with each other. - You can't have globals, statics, fields, or enums that are scope classes, but it seems they can be scope structs. (Hence, there can be no outward propagation of the scope class qualifier either.) - You can't take the address of a scope struct, but you can take the address of a scope class reference. - A scope class variable must be declared with scope, but your example indicates that that's not the idea for scope structs.
 This is as much as we have in terms of a design right now, so definitely 
 it stands some more fleshing out. If gotten right, scope should allow 
 defining a number of useful idioms, such as pass-down values, 
 unique/lent objects, and the such.

What are pass-down values? (Yes, I've tried searching for it.)
 Working against escapes has long been a problem, and with scope we're 
 hoping to strike a balance between useful and simple.
 
 Please share any thoughts you might have.

In brief: I like the idea, but I like the ' disable opUnary!"&"' suggestion better than 'scope struct'. -Lars
Feb 08 2010
next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Lars T. Kyllingstad wrote:
 Though the feature seems useful, I worry about the asymmetry with scope 
 classes.  I think it will be very confusing to new D programmers that a 
 scope class and a scope struct have very little to do with each other.

I agree, except I more and more think that scope classes were a mistake. Structs with destructors are a much better solution, and wrapping a class inside a struct would give it RAII semantics.
Feb 08 2010
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2/8/10 11:05, Walter Bright wrote:
 Lars T. Kyllingstad wrote:
 Though the feature seems useful, I worry about the asymmetry with
 scope classes. I think it will be very confusing to new D programmers
 that a scope class and a scope struct have very little to do with each
 other.

I agree, except I more and more think that scope classes were a mistake. Structs with destructors are a much better solution, and wrapping a class inside a struct would give it RAII semantics.

Scope class seems like a workaround in D1 because it doesn't got structs with constructors and destructors. If scope classes are up for removal shouldn't struct constructors be fixed to allow to do the same as class constructors? For example, allow empty parameter lists. /Jacob Carlborg
Feb 08 2010
prev sibling parent Kagamin <spam here.lot> writes:
Walter Bright Wrote:

 Lars T. Kyllingstad wrote:
 Though the feature seems useful, I worry about the asymmetry with scope 
 classes.  I think it will be very confusing to new D programmers that a 
 scope class and a scope struct have very little to do with each other.

I agree, except I more and more think that scope classes were a mistake. Structs with destructors are a much better solution, and wrapping a class inside a struct would give it RAII semantics.

stack allocs will be quite a hack...
Feb 08 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Lars T. Kyllingstad wrote:
 Andrei Alexandrescu wrote:
 Following work on typechecking synchronized methods, Walter and I were 
 discussing about managing escaping references to objects that wouldn't 
 actually agree to escaping. The problem is that today a value has no 
 idea that its address is being taken, so it has no saying in that.

 To compensate for that, my idea was to allow  disable on opUnary!"&". 
 Walter suggested allowing "scope" as a property of a struct:

 scope struct Transitory
 {
     ...
 }

 A scope struct cannot have its address taken. You can take addresses 
 of its members (access permitting), but you can't take the address of 
 any other struct that has at least one scope struct as a direct 
 member. For example:

 struct A
 {
     int x;
     Transitory tr;
 }

 A will also be scope. So scope has this funny way of propagating 
 outwards, as opposed to qualifiers, which propagate inwards.

Though the feature seems useful, I worry about the asymmetry with scope classes.

Scope classes will be eliminated from the language. Andrei
Feb 08 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrei Alexandrescu:
 Scope classes will be eliminated from the language.

Isn't it better to remove scope classes after a good escape analysis is implemented in the front-end? Bye, bearophile
Feb 08 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
bearophile wrote:
 Andrei Alexandrescu:
 Scope classes will be eliminated from the language.

Isn't it better to remove scope classes after a good escape analysis is implemented in the front-end?

Escape analysis can still be used to put class instantiations on the stack - it's just that that will be a compiler optimization, not a user one.
Feb 13 2010
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from Walter Bright (newshound1 digitalmars.com)'s article
 bearophile wrote:
 Andrei Alexandrescu:
 Scope classes will be eliminated from the language.

Isn't it better to remove scope classes after a good escape analysis is implemented in the front-end?

stack - it's just that that will be a compiler optimization, not a user one.

But the compiler has to be relatively conservative about this, whereas the user can take advantage of knowing how his/her program works at a high level. That said, I'm in favor of removing scope classes from the core language because their RAII purpose has been taken over by structs and their optimization purpose should be fulfilled via an uglier, more dangerous looking and more general library construct. Such a library construct should also allow strong class instances inline in other class instances.
Feb 13 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
dsimcha:
Such a library construct should also allow strong class instances inline in
other class instances.<

How can this be done? Is it possible to take any class and instantiate it with a placement new inside another class instance? I'd like to see a bit of the implementation code. Thank you, bye, bearophile
Feb 14 2010
parent reply dsimcha <dsimcha yahoo.com> writes:
== Quote from bearophile (bearophileHUGS lycos.com)'s article
 dsimcha:
Such a library construct should also allow strong class instances inline in


 How can this be done? Is it possible to take any class and instantiate it with
a

implementation code.
 Thank you, bye,
 bearophile

Here's a quick and dirty implementation. I haven't thought about how to work out all the details yet: 1. If the class contains immutable members, this implementation allows for overwriting immutable data. 2. I don't know how to give the struct proper type information so that the GC won't scan it if it doesn't contain any pointers. Right now I'm using void[], which needs to always be conservatively scanned. 3. The way I handled c'tors isn't going to work with ref parameters, etc. import std.stdio; struct InlineClass(C) { enum instanceSize = __traits(classInstanceSize, C); void[instanceSize] space = void; this(T...)(T args) { space[] = typeid(C).init[]; instance.__ctor(args); } C instance() { return cast(C) cast(void*) &this; } alias instance this; } class Foo { uint n; this(uint startVal) { n = startVal; } void printN() { writeln("Called printN for the ", n++, "th time."); } } void main() { auto foo = InlineClass!Foo(5); foo.printN(); foo.printN(); }
Feb 14 2010
parent bearophile <bearophileHUGS lycos.com> writes:
dsimcha:
 Here's a quick and dirty implementation.  I haven't thought about how to work
out
 all the details yet:

Thank you for your code, I'll try it. If some of the problems you talk about can't be currently solved, then I think D2 has to be improved/modified to allow all those problems to be fully solved :-) I think it's important to create a flexible language. That's why I have asked for some code here. If the language can't be modified enough to solve all those problems, then it's better to not remove (yet) the scope classes from D2 (the same is true for foreach_reverse). Bye, bearophile
Feb 14 2010
prev sibling next sibling parent Michel Fortin <michel.fortin michelf.com> writes:
On 2010-02-08 00:27:29 -0500, Andrei Alexandrescu 
<SeeWebsiteForEmail erdani.org> said:

 Following work on typechecking synchronized methods, Walter and I were 
 discussing about managing escaping references to objects that wouldn't 
 actually agree to escaping. The problem is that today a value has no 
 idea that its address is being taken, so it has no saying in that.
 
 To compensate for that, my idea was to allow  disable on opUnary!"&". 
 Walter suggested allowing "scope" as a property of a struct:
 
 scope struct Transitory
 {
      ...
 }
 
 A scope struct cannot have its address taken. You can take addresses of 
 its members (access permitting), but you can't take the address of any 
 other struct that has at least one scope struct as a direct member. For 
 example:

Are you saying by "you can take addresses of its member" that it's up to the struct implementation to not leak the address of a member? (by making members private and propagating access only through proxy scope structs?) I'd say that it looks useful, but it can't do much by itself. That's just one piece of the puzzle and without other pieces it won't go very far. Consider this: scope struct Transitory(O) { private O o; this(string s) { o = new O(s); } string toString() { return o.toString(); } } Transitory!MyObject t = Transitory!MyObject("hello"); t.toString(); This code has two issues: 1. MyObject's constructor could leak a reference. 2. MyObject's toString could leak a reference. Do we need a "scope class" for this to work?
 A scope struct cannot have its address taken. You can take addresses of 
 its members (access permitting), but you can't take the address of any 
 other struct that has at least one scope struct as a direct member. For 
 example:
 
 struct A
 {
      int x;
      Transitory tr;
 }
 
 A will also be scope. So scope has this funny way of propagating 
 outwards, as opposed to qualifiers, which propagate inwards.

I'm not sure why you need that. If Transitory is scope, then you can't take tr's address. Taking the address of A doesn't give you the address of tr (in reality it might be the same address, but it'll be typed as A and won't allow you to get the address of tr anyway). So why does A need to be scope?
 This is as much as we have in terms of a design right now, so 
 definitely it stands some more fleshing out. If gotten right, scope 
 should allow defining a number of useful idioms, such as pass-down 
 values, unique/lent objects, and the such.

That'd be really great. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Feb 08 2010
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
Andrei Alexandrescu wrote:
 Following work on typechecking synchronized methods, Walter and I were 
 discussing about managing escaping references to objects that wouldn't 
 actually agree to escaping. The problem is that today a value has no 
 idea that its address is being taken, so it has no saying in that.
 
 To compensate for that, my idea was to allow  disable on opUnary!"&". 
 Walter suggested allowing "scope" as a property of a struct:
 
 scope struct Transitory
 {
     ...
 }
 
 A scope struct cannot have its address taken. You can take addresses of 
 its members (access permitting), but you can't take the address of any 
 other struct that has at least one scope struct as a direct member. For 
 example:
 
 struct A
 {
     int x;
     Transitory tr;
 }
 
 A will also be scope. So scope has this funny way of propagating 
 outwards, as opposed to qualifiers, which propagate inwards.
 
 This is as much as we have in terms of a design right now, so definitely 
 it stands some more fleshing out. If gotten right, scope should allow 
 defining a number of useful idioms, such as pass-down values, 
 unique/lent objects, and the such.
 
 Working against escapes has long been a problem, and with scope we're 
 hoping to strike a balance between useful and simple.
 
 Please share any thoughts you might have.

Why is this useful?
Feb 08 2010
parent Walter Bright <newshound1 digitalmars.com> writes:
Ary Borenszweig wrote:
 Why is this useful?

Many optimizations are possible if it can be unambiguously determined that an object's lifetime cannot exceed the lifetime of the function it is instantiated in. By preventing taking the address of it, there's no way to escape a reference to it.
Feb 13 2010
prev sibling parent Leandro Lucarella <llucax gmail.com> writes:
Walter Bright, el 13 de febrero a las 19:13 me escribiste:
 bearophile wrote:
Andrei Alexandrescu:
Scope classes will be eliminated from the language.

Isn't it better to remove scope classes after a good escape analysis is implemented in the front-end?

Escape analysis can still be used to put class instantiations on the stack - it's just that that will be a compiler optimization, not a user one.

LDC already have some heuristics for that: http://www.dsource.org/projects/ldc/browser/gen/passes/GarbageCollect2Stack.cpp -- Leandro Lucarella (AKA luca) http://llucax.com.ar/ ---------------------------------------------------------------------- GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05) ----------------------------------------------------------------------
Feb 13 2010