Am 14.07.2013 14:25, schrieb bearophile:
Benjamin Thaut:

Trying to use ClassCompose in my code I have had some problems caused
by const classes and ClassCompose dtor. Maybe such dtor
(and isDestructed) can be versioned out for composed-in classes
that only contain values...

Can you give an example for that?

As a simple example try to make this work:


struct UseDefaultCtor {}
/// Call default ctor type for Composition.
enum useDefaultCtor = UseDefaultCtor();


struct Composition(T) if (is(T == class)) {
     void[__traits(classInstanceSize, T)] classInstanceBuf = void;
     bool isDestructed = false;

     @property T _instance() {
         return cast(T)classInstanceBuf.ptr;
     }

     @property const(T) _instance() const {
         return cast(const T)classInstanceBuf.ptr;
     }

     alias _instance this;

     @disable this();
     @disable this(this);

     this()(UseDefaultCtor) {
         classInstanceBuf[] = typeid(T).init[];
         _instance.__ctor;
     }

     this(Targs...)(Targs args)
     if (__traits(compiles, _instance.__ctor(args))) {
         classInstanceBuf[] = typeid(T).init[];
         _instance.__ctor(args);
     }

     ~this() {
         if (!isDestructed) {
             _instance.destroy;
             isDestructed = true;
         }
     }
}

// ----------------------------------

const class Foo {
     int x;
     this(int xx) const pure nothrow {
         this.x = x;
     }
}

const class Bar {
     const Composition!Foo f;

     this(int x) const pure nothrow {
         f = typeof(f)(x);
     }
}

void main() {}


Yes your little example perfectly illustrates a few shortcommings of the D type system. Thats the best I could do:

struct Composition(T) if (is(T == class)) {
    void[__traits(classInstanceSize, T)] classInstanceBuf = void;
    bool isDestructed = false;

    @property T _instance() {
        return cast(T)classInstanceBuf.ptr;
    }

    @property const(T) _instance() const {
        return cast(const T)classInstanceBuf.ptr;
    }

    alias _instance this;

    //@disable this();
    @disable this(this);

    /*this()(UseDefaultCtor) {
        classInstanceBuf[] = typeid(T).init[];
        _instance.__ctor;
    }*/

    this(Targs...)(Targs args) const pure nothrow
    if (__traits(compiles, _instance.__ctor(args))) {
        classInstanceBuf[] = typeid(T).init[];
        _instance.__ctor(args);
    }

    ~this() pure const {
        if (!isDestructed) {
                        static if(is(typeof(_intance.__dtor)))
                                _instance.__dtor();
        }
    }
}

But the compiler is still trying to call opAssign inside the constructor of Bar. I'm not sure if that isn't actually a bug. But the main problem here is that you can not deduce the attributes of the given type to the constructor and destructor of the helper struct. Maybe something like the following would be possible:

static if(isPure!(T.__ctor))
{
  static if(isConst!(T.__ctor))
  {
    this(Targs)(Targs args) pure const { ... }
  }
  else
  {
    this(Targs)(Targs args) pure { ... }
  }
}
else
{
  static if(isConst!(T.__ctor))
  {
    this(Targs)(Targs args) const { ... }
  }
  else
  {
    this(Targs)(Targs args) { ... }
  }
}

And so on.

Or you use a string-mixin to generate the equivalent of all constructors inside the helper struct.

Genereally there are still so many bugs connected with structs in D that it is not fun doing advanced things with structs most of the time.



Maybe such alignment can be added to the ClassCompose too.


But that would be a uneccessary overhead. Just adding a align(4) or
align(16) like suggested below would be sufficient.

I don't understand. What overhead? It's an annotation that depends on
the contents of ClassCompose. I think it should cause no bad overhead.

Bye,
bearophile

Phobos scoped makes the void array bigger then needed because the scoped struct might not be properly aligend on the stack. Then inside the constructor scoped manually aligns the instance to the correct alignment using the bytes previously added to the buffer. Lets say you use it inside a class, and the struct already happens to be correctly aligned, then the additional bytes will be vasted and introcude a unccessary overhead. So it is better to annotate the CompositeClass sturct with a align attribute because the compiler will then only introduce additional padding if actually needed.

Kind Regards
Benjamin Thaut

Reply via email to