March 09, 2009
On Sat, 07 Mar 2009 08:15:59 +0300, John Simon <zildjohn01@gmail.com> wrote:

> I'd like to propose a new use for the 'scope' keyword within an aggregate body.
>
> Members of class type declared with the scope keyword are allocated not as references or pointers, but initialized directly inside the container.  Instead of a default initializer of 'null', it will initialize with the default constructor of the class, or an optional assignment after the declaration. Any 'new [type]' within the assignment will resolve to a simple call to the type's __ctor, instead of a memory allocation.
>
> Example:
>
> class Inner {
>     this() {}
>     this(int x) {}
> }
>
> class Container {
>     Inner i1; // initialized to null
>     scope Inner i2; // allocated within class
>     scope i3 = new Inner(42); // allocated within class
>
>     this() {
>         // implicit i2.__ctor();
>         // i3.__ctor(42) written above, executed here
>         assert(i1 is null);
>         assert(i2 !is null);
>         i1 = new Inner;
>     }
>
>     this(int overloaded) {
>         // i2 and i3 are constructed, same as above
>     }
>
>     ~this() {
>         // implicit i2.__dtor();
>         // implicit i3.__dtor();
>         // i1 is still somewhere in the heap
>     }
> }
>
> IN ENGLISH:
>
> If it's likely that class members will be constructed with and die with the object, why not just allocate them right in the class? Save on heap fragmentation and cache misses.  I was honesetly flabberghasted when I realized there was no way to do this in D, it seems like it should be one of the most basic constructs of a C-derived (or any low-ish level) language.
>
> The programmer knows best where he wants his objects stored. Also, the 'scope' makes sense, and we should mirror the current behavior of the keyword in function bodies.

I belive it could be implemented in a library. Something like this (not tested):

struct Scope(T)
{
   static assert(is(T : class));

   private ubyte[SizeOf!(T)] _data = T.init[];
   private bool _isConstructed = false;

   T value()
   {
       return cast(T)_data.ptr;
   }

   alias this value;

   void construct(Params...)(Params params) // perhaps, could be 'this'
   {
       assert(!_isConstructed);
       value.ctor(params);
       _isConstructed = true;
   }
}

Usage:

class Foo {
   this(int i) { this.i = i; }
   int i;
   void doSomething() { }
}

class Bar
{
   Scope!(Foo) foo;

   this()
   {
       // optional:
       foo.construct(42); // different syntax is also possible
       // same as foo = new Foo(42);

       Foo f = foo; // implicit cast
       foo.doSomething();
       int i = foo.i;         }
}

March 09, 2009
Yigal Chripun Wrote:

> On 09/03/2009 00:12, John Simon wrote:
> > Sean Kelly Wrote:
> >
> >> John Simon wrote:
> >>> Sean Kelly Wrote:
> >>>> Oh, I should mention that I'm not sure how the compiler would handle this scenario:
> >>>>
> >>>> class A { byte[16]; } class B { byte[32]; } class C { this(
> >>>> bool b ) { if( b ) o = new A; else    o = new B; } scope Object
> >>>> o; }
> >>>>
> >>>> If I had to guess I'd say that the compiler would either reserve the max size necessary to store both A or B, or that in non-trivial cases it just wouldn't bother with reserving space for o at all.
> >>> Wrong. The Object is constructed when it comes into scope, and destructed when it leaves scope. Classes can't have an 'opAssign', instead the reference is reassigned. Since the reference is invariant/immutable here, this throws a compile time error.
> >> I'm talking about a proposed new feature, not an existing one. Please take this example in context.
> >
> > Sorry man, I thought you were disputing with me. My apologies. Let me rephrase.
> >
> > I believe that 'scope' declared objects shouldn't allow an assignment of a derived type. Reasoning being that there wouldn't be enough stack space allocated for it.
> >
> > So in your example above, Object could only recieve a 'new Object', and nothing further down in the hierarchy.
> 
> how can the compiler enforce such a rule?
> 
> class A { byte[16]; }
> class B : A { byte[32]; }
> 
> class C {
>     this(A a) { obj = a; }
>     scope A obj;
> }

My proposal was to make scope object construction and destruction automatic and implicit, meaning any assignment would be illegal, besides an inline construction by the definition of the same type as the scope variable.

However even if that restriction wasn't there, the runtime could restrict it the same way it does dynamic casting. I see no point to doing it this second way though.
March 09, 2009
Denis Koroskin Wrote:

> On Sat, 07 Mar 2009 08:15:59 +0300, John Simon <zildjohn01@gmail.com> wrote:
> 
> > I'd like to propose a new use for the 'scope' keyword within an aggregate body.
> >
> > Members of class type declared with the scope keyword are allocated not as references or pointers, but initialized directly inside the container.  Instead of a default initializer of 'null', it will initialize with the default constructor of the class, or an optional assignment after the declaration. Any 'new [type]' within the assignment will resolve to a simple call to the type's __ctor, instead of a memory allocation.
> >
> > Example:
> >
> > class Inner {
> >     this() {}
> >     this(int x) {}
> > }
> >
> > class Container {
> >     Inner i1; // initialized to null
> >     scope Inner i2; // allocated within class
> >     scope i3 = new Inner(42); // allocated within class
> >
> >     this() {
> >         // implicit i2.__ctor();
> >         // i3.__ctor(42) written above, executed here
> >         assert(i1 is null);
> >         assert(i2 !is null);
> >         i1 = new Inner;
> >     }
> >
> >     this(int overloaded) {
> >         // i2 and i3 are constructed, same as above
> >     }
> >
> >     ~this() {
> >         // implicit i2.__dtor();
> >         // implicit i3.__dtor();
> >         // i1 is still somewhere in the heap
> >     }
> > }
> >
> > IN ENGLISH:
> >
> > If it's likely that class members will be constructed with and die with the object, why not just allocate them right in the class? Save on heap fragmentation and cache misses.  I was honesetly flabberghasted when I realized there was no way to do this in D, it seems like it should be one of the most basic constructs of a C-derived (or any low-ish level) language.
> >
> > The programmer knows best where he wants his objects stored. Also, the 'scope' makes sense, and we should mirror the current behavior of the keyword in function bodies.
> 
> I belive it could be implemented in a library. Something like this (not tested):
> 
> struct Scope(T)
> {
>     static assert(is(T : class));
> 
>     private ubyte[SizeOf!(T)] _data = T.init[];
>     private bool _isConstructed = false;
> 
>     T value()
>     {
>         return cast(T)_data.ptr;
>     }
> 
>     alias this value;
> 
>     void construct(Params...)(Params params) // perhaps, could be 'this'
>     {
>         assert(!_isConstructed);
>         value.ctor(params);
>         _isConstructed = true;
>     }
> }
> 
> Usage:
> 
> class Foo {
>     this(int i) { this.i = i; }
>     int i;
>     void doSomething() { }
> }
> 
> class Bar
> {
>     Scope!(Foo) foo;
> 
>     this()
>     {
>         // optional:
>         foo.construct(42); // different syntax is also possible
>         // same as foo = new Foo(42);
> 
>         Foo f = foo; // implicit cast
>         foo.doSomething();
>         int i = foo.i;
>     }
> }
> 

Oh man I've tried, believe me.
I couldn't figure out how to call the destructors in-place. Also, structs can't have parameter-less constructors
March 10, 2009
John Simon wrote:
> 
> Oh man I've tried, believe me.
> I couldn't figure out how to call the destructors in-place. Also, structs can't have parameter-less constructors

Have you tried just calling delete on the reference?  That should do what you want.  In D2 it certainly will at any rate... I haven't looked at the D1 lib source in a while.
March 12, 2009
Sean Kelly Wrote:

> John Simon wrote:
> > 
> > Oh man I've tried, believe me.
> > I couldn't figure out how to call the destructors in-place. Also, structs can't have parameter-less constructors
> 
> Have you tried just calling delete on the reference?  That should do what you want.  In D2 it certainly will at any rate... I haven't looked at the D1 lib source in a while.

That would call __dtor, but wouldn't it also screw up the garbage collector or allocator?  Since the bytes would be located at offset 0 in the struct, wouldn't it try to free the same memory twice?

Also I'm guessing there's no viable solution to the constructor problem, besides a mandatory member function. Which kills a lot of the elegance this type of construct would create
1 2 3
Next ›   Last »