www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - scope as template struct

reply Christian Kamm <kamm-incasoftware removethis.de> writes:
With the features of D2 you can get pretty close to implementing scope
classes as a template struct:

private final class PlacementNewClass(T) : T
{
  // forward constructors here!

  new(uint size, byte[__traits(classInstanceSize, PlacementNewClass)] mem) {
    return &mem;
  }
  delete(void* addr) {}
}

struct StackClass(T)
{
  // forward constructors here!
  void construct() { 
    new(memory) PlacementNewClass!(T);
  }

  ~this() {
    T tmp = cast(T)this;
    delete tmp;
  }

  // should be opImplicitCast
  T opCast() { return cast(T)cast(void*)&memory; }
  T opDot() { return cast(T)cast(void*)&memory; }

  byte[__traits(classInstanceSize, PlacementNewClass!(T))] memory;
}

Instances of StackClass!(C) behave pretty much like scope C, except they are
not limited to function local variables.

Unless there's a major difference to 'scope' I missed, I think that with the
addition of a few generic features it should be possible to move it into a
library entirely. In particular, D would need opImplicitCast as well as a
way of accessing and forwarding constructors to make this work nicely.
Jan 13 2009
parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Christian Kamm wrote:
 With the features of D2 you can get pretty close to implementing scope
 classes as a template struct:
 
 private final class PlacementNewClass(T) : T
 {
   // forward constructors here!
 
   new(uint size, byte[__traits(classInstanceSize, PlacementNewClass)] mem) {
     return &mem;
   }
   delete(void* addr) {}
 }
 
 struct StackClass(T)
 {
   // forward constructors here!
   void construct() { 
     new(memory) PlacementNewClass!(T);
   }
 
   ~this() {
     T tmp = cast(T)this;
     delete tmp;
   }
 
   // should be opImplicitCast
   T opCast() { return cast(T)cast(void*)&memory; }
   T opDot() { return cast(T)cast(void*)&memory; }
 
   byte[__traits(classInstanceSize, PlacementNewClass!(T))] memory;
 }
 
 Instances of StackClass!(C) behave pretty much like scope C, except they are
 not limited to function local variables.
 
 Unless there's a major difference to 'scope' I missed, I think that with the
 addition of a few generic features it should be possible to move it into a
 library entirely. In particular, D would need opImplicitCast as well as a
 way of accessing and forwarding constructors to make this work nicely.

Yes this would be possible. But what's the advantage of doing it this way and is it worth sacrificing syntax sugar and backwards compatibility for? And would this even work right with RAII?
Jan 13 2009
parent reply Christian Kamm <kamm-incasoftware removethis.de> writes:
Christian Kamm wrote:
 Unless there's a major difference to 'scope' I missed, I think that with
 the addition of a few generic features it should be possible to move it
 into a library entirely.


Robert Fraser wrote:
 Yes this would be possible. But what's the advantage of doing it this
 way and is it worth sacrificing syntax sugar and backwards compatibility
 for? And would this even work right with RAII?

For the same reason that std.typecons.Rebindable isn't in the language but in a library: if you can build it out of other features, it's not worth making the language more complicated by adding it explicitly. I agree that there's a fine line where ease of use conflicts with orthogonality, but in this case not much sugar seems to be lost. About RAII: The wrapped classes' constructor and destructor are called just fine at the right time. There is a bug that the destructor will probably segfault if construct() wasn't called, but that should be avoidable either by having a flag set on construction or somehow forcing construction during initialization.
Jan 13 2009
parent reply Eldar Insafutdinov <e.insafutdinov nowhere.com> writes:
Christian Kamm Wrote:

 Christian Kamm wrote:
 Unless there's a major difference to 'scope' I missed, I think that with
 the addition of a few generic features it should be possible to move it
 into a library entirely.


Robert Fraser wrote:
 Yes this would be possible. But what's the advantage of doing it this
 way and is it worth sacrificing syntax sugar and backwards compatibility
 for? And would this even work right with RAII?

For the same reason that std.typecons.Rebindable isn't in the language but in a library: if you can build it out of other features, it's not worth making the language more complicated by adding it explicitly. I agree that there's a fine line where ease of use conflicts with orthogonality, but in this case not much sugar seems to be lost. About RAII: The wrapped classes' constructor and destructor are called just fine at the right time. There is a bug that the destructor will probably segfault if construct() wasn't called, but that should be avoidable either by having a flag set on construction or somehow forcing construction during initialization.

Jan 16 2009
parent Christian Kamm <kamm-incasoftware removethis.de> writes:
Christian Kamm wrote:
 Unless there's a major difference to 'scope' I missed, I think that
 with the addition of a few generic features it should be possible to
 move it into a library entirely.




Robert Fraser wrote:
 Yes this would be possible. But what's the advantage of doing it this
 way and is it worth sacrificing syntax sugar and backwards
 compatibility for? And would this even work right with RAII?



Christian Kamm Wrote:
 For the same reason that std.typecons.Rebindable isn't in the language
 but in a library: if you can build it out of other features, it's not
 worth making the language more complicated by adding it explicitly. I
 agree that there's a fine line where ease of use conflicts with
 orthogonality, but in this case not much sugar seems to be lost.
 
 About RAII: The wrapped classes' constructor and destructor are called
 just fine at the right time. There is a bug that the destructor will
 probably segfault if construct() wasn't called, but that should be
 avoidable either by having a flag set on construction or somehow forcing
 construction during initialization.


Eldar Insafutdinov wrote:
 and in this case where would be class allocated? On heap? scope allocates
 classes on the stack afaik.

In the case that construct() isn't called? There'd be stack space reserved for the class, but no object constructed inside. The template I posted doesn't touch the heap at all.
Jan 16 2009