July 14, 2013
On Sunday, 14 July 2013 at 12:28:48 UTC, Dicebot wrote:
> On Saturday, 13 July 2013 at 12:47:28 UTC, bearophile wrote:
>> ...

P.S. but reading scoped docs I got no idea if this is a legal
safe usage.
July 14, 2013
Am 14.07.2013 14:03, schrieb bearophile:
> Benjamin Thaut:
>
>> I just noticed that this still does not work. Even with dmd 2.063 I
>> get the error message:
>>
>> main.d(28): Error: template
>> main.ComposeClass!(Object).ComposeClass.__ctor(Targs...)(Targs args)
>> conflicts with constructor
>> main.ComposeClass!(Object).ComposeClass.this at main.d(20)
>>
>> If you have a templated constructor you can't have any non templated
>> constructors. (http://d.puremagic.com/issues/show_bug.cgi?id=4749)
>> So a version with a templated constructor is still not doable at the
>> moment.
>
> Sorry, I forgot to say that I am using this:
>
>      this()(UseDefaultCtor) {
>          classInstanceBuf[] = typeid(T).init[];
>          _instance.__ctor;
>      }
>
> Bye,
> bearophile

This still doesn't work for me. The compiler (2.063.2) will tell me that it conflicts with

@disable this();

Does this actually work for you?

Kind Regards
Benjamin Thaut
July 14, 2013
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

July 14, 2013
Benjamin Thaut:

> Does this actually work for you?

It seems to work. (But in that little program I have found two new unrelated compiler bugs that don't allow me to compile the program in an useful way. I have reported both of them in Bugzilla and one of them has now a patch, so probably I will not have to wait a lot).

Bye,
bearophile
July 14, 2013
Am 14.07.2013 16:25, schrieb bearophile:
> Benjamin Thaut:
>
>> Does this actually work for you?
>
> It seems to work. (But in that little program I have found two new
> unrelated compiler bugs that don't allow me to compile the program in an
> useful way. I have reported both of them in Bugzilla and one of them has
> now a patch, so probably I will not have to wait a lot).
>
> Bye,
> bearophile

Can you give a link to the two respective bugs please?
July 14, 2013
Benjamin Thaut:

> Can you give a link to the two respective bugs please?

I think they are:

http://d.puremagic.com/issues/show_bug.cgi?id=10629
http://d.puremagic.com/issues/show_bug.cgi?id=10632

The first has already a patch, and probably the second is a regression.

Bye,
bearophile
July 14, 2013
Dicebot:

> Hm, actually naive scoped usage seems to work for me:
>
> ---------------------------------------
> import std.typecons;
>
> class B
> {
> 	byte a;
> }
>
> class A
> {
> 	typeof(scoped!B()) b = void;
> 	
> 	this()
> 	{
> 		b = scoped!B();
> 	}
> }

Good. If I comment away most tags it seems to work:


import std.typecons;

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

/*const*/ class Bar {
    /*const*/ typeof(scoped!Foo(1)) f = void;

    this(int x) /*const pure nothrow*/ {
        // f = typeof(f)(x); // Can't be used.
        f = scoped!Foo(x);
    }
}

void main() {
    auto b = new Bar(10);
}


I will try it in my code to see if and how well it works.


I have seen code like this:

class Bar {
    const int[1000] x = void;
    this(int n) {
        x[] = n;
    }
}
void main() {}



That gives me:

test.d(2): Warning: const field with initializer should be static, __gshared, or an enum
test.d(4): Error: slice x[] is not mutable


Are those error messages right?

Bye,
bearophile
July 14, 2013
The warning comes from:
http://dlang.org/changelog.html#staticfields
July 14, 2013
Namespace:

> The warning comes from:
> http://dlang.org/changelog.html#staticfields

But is "void" an initializer?

Bye,
bearophile
July 14, 2013
On Sunday, 14 July 2013 at 15:28:26 UTC, bearophile wrote:
> Namespace:
>
>> The warning comes from:
>> http://dlang.org/changelog.html#staticfields
>
> But is "void" an initializer?
>
> Bye,
> bearophile

Seems so, but I don't know why. Anyway, it's obviously wrong, you should fill a bug report.