Thread overview
scope as template struct
Jan 13, 2009
Christian Kamm
Jan 14, 2009
Robert Fraser
Jan 14, 2009
Christian Kamm
Jan 16, 2009
Eldar Insafutdinov
Jan 16, 2009
Christian Kamm
January 13, 2009
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.

January 14, 2009
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?
January 14, 2009
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.

January 16, 2009
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.
> 
and in this case where would be class allocated? On heap? scope allocates classes on the stack afaik.
January 16, 2009
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.