digitalmars.D - "The last feature": scope structs
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Feb 07 2010
- "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> Feb 08 2010
- Walter Bright <newshound1 digitalmars.com> Feb 08 2010
- Jacob Carlborg <doob me.com> Feb 08 2010
- Kagamin <spam here.lot> Feb 08 2010
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Feb 08 2010
- bearophile <bearophileHUGS lycos.com> Feb 08 2010
- Walter Bright <newshound1 digitalmars.com> Feb 13 2010
- dsimcha <dsimcha yahoo.com> Feb 13 2010
- bearophile <bearophileHUGS lycos.com> Feb 14 2010
- dsimcha <dsimcha yahoo.com> Feb 14 2010
- bearophile <bearophileHUGS lycos.com> Feb 14 2010
- Michel Fortin <michel.fortin michelf.com> Feb 08 2010
- Ary Borenszweig <ary esperanto.org.ar> Feb 08 2010
- Walter Bright <newshound1 digitalmars.com> Feb 13 2010
- Leandro Lucarella <llucax gmail.com> Feb 13 2010
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
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
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
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
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
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
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
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
== Quote from Walter Bright (newshound1 digitalmars.com)'s articlebearophile 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
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
== Quote from bearophile (bearophileHUGS lycos.com)'s articledsimcha: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
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
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
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
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
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









Jacob Carlborg <doob me.com> 