July 13, 2013 Re: "Value class instance" pattern? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | On Saturday, 13 July 2013 at 16:19:06 UTC, Benjamin Thaut wrote:
> Yes this looks pretty similar to scoped in phobos but I always thought that scoped was inteded for objects to be placed on the stack instead of inside other objects. Thats also why scoped does some additional alignment which is garantueed when you do it within a class.
The alignment is guaranteed only for enclosing class, not for the composite struct. Though in case on embedding it's enough to add align(16), I suppose.
|
July 13, 2013 Re: "Value class instance" pattern? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Saturday, 13 July 2013 at 17:48:40 UTC, bearophile wrote:
> Kagamin:
>
>> emplace?
>
> Can you show a little compilable program that solves my problem using emplace?
Do you want just to construct unique instances of Foo in each Bar or you want to copy Foo by value like in C++?
|
July 13, 2013 Re: "Value class instance" pattern? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Kagamin | Kagamin:
> Do you want just to construct unique instances of Foo in each Bar or you want to copy Foo by value like in C++?
Construct an instance of Foo in Bar is enough.
(Copying Foo is nice but not necessary.)
Bye,
bearophile
|
July 14, 2013 Re: "Value class instance" pattern? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | Am 13.07.2013 18:41, schrieb bearophile:
> Benjamin Thaut:
>
>> I also wanted to mention the "ListAvailableCtors" template which is a
>> nice addition in case there is no constructor available to be called
>> with the given arguments. It will generate a list of all aviable ctors
>> with the types of its arguments, and thus greatly improve the error
>> message given when no appropriate constructor can be found:
>>
>> string ListAvailableCtors(T)()
>> {
>> string result = "";
>> foreach(t; __traits(getOverloads, T, "__ctor"))
>> result ~= typeof(t).stringof ~ "\n";
>> return result;
>> }
>>
>> In my original code it was used during construction like this:
>>
>> static if(is(typeof(result.__ctor(args))))
>> {
>> result.__ctor(args);
>> }
>> else
>> {
>> static assert(args.length == 0 && !is(typeof(T.__ctor)), "Don't know
>> how to initialize an object of type " ~ T.stringof ~ " with
>> arguments:\n" ~ ARGS.stringof ~ "\nAvailable ctors:\n" ~
>> ListAvailableCtors!T() );
>> }
>
> In my version of your code I have just added a template constraint, this
> is simpler, and it generates an error at the calling point:
>
> this(Targs...)(Targs args)
> if (__traits(compiles, _instance.__ctor(args))) {
> classInstanceBuf[] = typeid(T).init[];
> _instance.__ctor(args);
> }
>
> Isn't this enough?
>
> Bye,
> bearophile
The problem with your version is that you will get something like:
Can't call ComposedClass.this with arguments (int, int, float)
With my version you will get:
Can't initialize object of type 'Foo' with arguments (int, int, float) available ctors:
(int, int, int)
(int)
(float)
With my version you will instantly know what ctors are available and you don't have to go look it up in the sourcecode.
Kind Regards
Benjamin Thaut
|
July 14, 2013 Re: "Value class instance" pattern? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | Am 13.07.2013 18:49, schrieb bearophile: > Benjamin Thaut: > >> Yes the assignment in this(DefaultCtor) is needed, because the >> construction process of a D object is defined as: > > OK. > > >> The debugging values are needed because most debuggers won't be able >> to evaluate properties while debugging. > > OK. > > > Is that ClassCompose destructor enough (with something added for the > debug build)? > > ~this() { > if (!isDestructed) { > _instance.destroy; > isDestructed = true; > } > } Thats enough for the debug build. > > 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? > > >> Yes this looks pretty similar to scoped in phobos but I always thought >> that scoped was inteded for objects to be placed on the stack instead >> of inside other objects. > > Right. I think Scoped can't be used for class composition. > But isn't such ClassCompose enough for both purposes? Or is it better to > have in Phobos both Scoped and something similar to ClassCompose? > > >> Thats also why scoped does some additional alignment which is >> garantueed when you do it within a class. > > 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. Kind Regards Benjamin Thaut |
July 14, 2013 Re: "Value class instance" pattern? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | Am 13.07.2013 17:15, schrieb bearophile: > (Sorry, this post has gone in this newsgroup by mistake, but it's a > small mistake.) > > > To change and understand your code a bit (now the ComposeClass > constructor is a template) I have removed some of the tests and debug > code, but they should be added back later: > > > /* > string listAvailableCtors(T)() { > string result = ""; > foreach(t; __traits(getOverloads, T, "__ctor")) > result ~= typeof(t).stringof ~ "\n"; > return result; > } > */ > > struct DefaultCtor {} //call default ctor type > enum defaultCtor = DefaultCtor(); > > struct ComposeClass(T) if (is(T == class)) { > void[__traits(classInstanceSize, T)] _classMemory = void; > bool m_destructed = false; > > @property T _instance() { > return cast(T)_classMemory.ptr; > } > > @property const(T) _instance() const { > return cast(const(T))_classMemory.ptr; > } > > alias _instance this; > > @disable this(); > @disable this(this); > > this(DefaultCtor) { > // _classMemory[] = typeid(T).init[]; // needed? > _instance.__ctor; > } > > this(Targs...)(Targs args) { > _classMemory[] = typeid(T).init[]; > _instance.__ctor(args); > } > > ~this() { > if (!m_destructed) { > _instance.destroy; > m_destructed = true; > } > } > } > > // Usage example ---------- > > class Foo { > int i, j; > this() { > this.i = 5; > } > > this(int ii) { > this.i = ii; > } > } > > class Bar { > ComposeClass!Foo f; > > this() { > //f = typeof(f)(defaultCtor); > f = typeof(f)(2); // alternative > } > } > > void main() { > import std.stdio; > auto bar = new Bar; > writeln(bar.f.i); > bar.f.i = 1; > writeln(bar.f.i); > } > > > This code is unfinished. > Is the assignment needed in this(DefaultCtor)? > > This code contains some sharp edges (for the D programmer and even for > the compiler, I have opened a new bug report: > http://d.puremagic.com/issues/show_bug.cgi?id=10629 ), for me it's easy > to get wrong, hard to get right & good, and I believe it's of general > usefulness, so I think it's fit for Phobos. > > But isn't it a replacement for Phobos Scoped? > > Bye, > bearophile 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. Kind Regards Benjamin Thaut |
July 14, 2013 Re: "Value class instance" pattern? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | 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
|
July 14, 2013 Re: "Value class instance" pattern? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | Benjamin Thaut:
> With my version you will instantly know what ctors are available and you don't have to go look it up in the sourcecode.
Right. On the other hand this is what happens when you call any constructor or any overloaded function. So I don't think it's so important.
One possible difference I see between my simpler ComposedClass and normal overloaded functions/constructors is that with ComposedClass an IDE can't give you a list of suggestions... So perhaps your idea is useful for D programmers that use an IDE.
Bye,
bearophile
|
July 14, 2013 Re: "Value class instance" pattern? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Benjamin Thaut | 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() {} >> 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 |
July 14, 2013 Re: "Value class instance" pattern? | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Saturday, 13 July 2013 at 12:47:28 UTC, bearophile wrote: > ... 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(); } } --------------------------------------- ...with only exception (bug?) - I can't default-construct A on heap after that. It works as expected if I created A via scoped or use non-default constructor. |
Copyright © 1999-2021 by the D Language Foundation