digitalmars.D.learn - Using private constructor with std.experimental.allocater:make
- earthfront (43/43) May 01 2016 Hello!
- Lass Safin (3/8) May 01 2016 I don't think classes are supposed to be able to have a private
- Jonathan M Davis via Digitalmars-d-learn (13/21) May 01 2016 On Sun, 01 May 2016 18:27:51 +0000
- Basile B (62/105) May 01 2016 __ctor is not enough, the "static layout" must be copied to get
- earthfront (18/26) May 01 2016 This works. Thank you. Good point about __ctor alone not being
- Basile B (7/34) May 01 2016 Other solution: give "super powers" to the __traits()... used to
Hello! This code fails: ------------------------- void main(){ class A { int b; private this(int a){b=a;} } //{ int b; this(int a){b=a;} } import std.conv:emplace; import std.experimental.allocator.mallocator:Mallocator; import std.experimental.allocator:make; { auto ptr = make!A(Mallocator.instance, 42); assert (ptr.b == 42); } } --------------------------- with error message: "/usr/include/dmd/phobos/std/conv.d(4115): Error: static assert "Don't know how to initialize an object of type A with arguments (int)" /usr/include/dmd/phobos/std/experimental/allocator/package.d(456): instantiated from here: emplace!(A, int) ./helloworld.d(25): instantiated from here: make!(A, shared(Mallocator), int)" If I make the constructor public, no problem. It seems that emplace (specialized for classes) doesn't work if the class has a private constructor. I added the following snippet to confirm: ---------------------- { auto ptr = Mallocator.instance.allocate(__traits(classInstanceSize, A)); auto aPtr = emplace(ptr,34); assert( aPtr.b == 34 ); } ---------------------- And I get the same error message. Google gave me: http://forum.dlang.org/post/kot0t1$uls$1 digitalmars.com That guy's ultimate fix was explicitly calling the class's __ctor method, instead of emplace. The __ctor method is undocumented, as far as I can tell. Is there a better solution now? More widespread use of allocators will likely result in more of this problem.
May 01 2016
On Sunday, 1 May 2016 at 11:17:27 UTC, earthfront wrote:Hello! [...] class A { int b; private this(int a){b=a;} } [...]I don't think classes are supposed to be able to have a private constructor...
May 01 2016
On Sun, 01 May 2016 18:27:51 +0000 Lass Safin via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:On Sunday, 1 May 2016 at 11:17:27 UTC, earthfront wrote:There's no reason why you shouldn't be able to. Other, public constructors could call it, and other code within the module could call it. You can even have entire classes which are private. So, private constructors need to be possible. Now, whether that will ever work with something like emplace or the allocators, I don't know, since they're going to have access to the constructor to do their thing, but they're in different modules, which wouldn't normally have access to any constructors which aren't private (including protected and package, not just private). - Jonathan M DavisHello! [...] class A { int b; private this(int a){b=a;} } [...]I don't think classes are supposed to be able to have a private constructor...
May 01 2016
On Sunday, 1 May 2016 at 11:17:27 UTC, earthfront wrote:Hello! This code fails: ------------------------- void main(){ class A { int b; private this(int a){b=a;} } //{ int b; this(int a){b=a;} } import std.conv:emplace; import std.experimental.allocator.mallocator:Mallocator; import std.experimental.allocator:make; { auto ptr = make!A(Mallocator.instance, 42); assert (ptr.b == 42); } } --------------------------- with error message: "/usr/include/dmd/phobos/std/conv.d(4115): Error: static assert "Don't know how to initialize an object of type A with arguments (int)" /usr/include/dmd/phobos/std/experimental/allocator/package.d(456): instantiated from here: emplace!(A, int) ./helloworld.d(25): instantiated from here: make!(A, shared(Mallocator), int)" If I make the constructor public, no problem. It seems that emplace (specialized for classes) doesn't work if the class has a private constructor. I added the following snippet to confirm: ---------------------- { auto ptr = Mallocator.instance.allocate(__traits(classInstanceSize, A)); auto aPtr = emplace(ptr,34); assert( aPtr.b == 34 ); } ---------------------- And I get the same error message. Google gave me: http://forum.dlang.org/post/kot0t1$uls$1 digitalmars.com That guy's ultimate fix was explicitly calling the class's __ctor method, instead of emplace. The __ctor method is undocumented, as far as I can tell. Is there a better solution now? More widespread use of allocators will likely result in more of this problem.__ctor is not enough, the "static layout" must be copied to get the status of the initialized variables. Also there is not always a __ctor. Anyway you can put this in the module where is located the class with a private ctor: ---- import std.traits; CT make(CT, Alloc, A...)(auto ref Alloc al, A a) if (is(CT == class) && !isAbstractClass!CT) { auto size = typeid(CT).init.length; auto memory = al.allocate(size); memory[0 .. size] = typeid(CT).init[]; static if (__traits(hasMember, CT, "__ctor")) (cast(CT) (memory.ptr)).__ctor(a); import core.memory: GC; GC.addRange(memory.ptr, size, typeid(CT)); return cast(CT) memory.ptr; } void main(string[] args) { class A {int b; private this(int a){b=a;} } import std.experimental.allocator.mallocator; auto ptr = make!A(Mallocator.instance, 42); assert (ptr.b == 42); } ---- The problem is that the template make and emplace() are **elsewhere** so they cannot see A.this() (== A.__ctor). A common way to fix this kind of problem is to make a template mixin with the template that has the visibility and to mix it in the current scope: ---- module stuff ----- mixin template fixProtection() { import std.traits; CT make(CT, Alloc, A...)(auto ref Alloc al, A a) if (is(CT == class) && !isAbstractClass!CT) { auto size = typeid(CT).init.length; auto memory = al.allocate(size); memory[0 .. size] = typeid(CT).init[]; static if (__traits(hasMember, CT, "__ctor")) (cast(CT) (memory.ptr)).__ctor(a); import core.memory: GC; GC.addRange(memory.ptr, size, typeid(CT)); return cast(CT) memory.ptr; } } ----- ----- module other stuff ----- mixin fixProtection; void main(string[] args) { class A {int b; private this(int a){b=a;} } import std.experimental.allocator.mallocator; auto ptr = make!A(Mallocator.instance, 42); assert (ptr.b == 42); } ----- Many things related to __traits are affected (getMember, getOverload, ...).
May 01 2016
On Sunday, 1 May 2016 at 19:18:38 UTC, Basile B wrote:CT make(CT, Alloc, A...)(auto ref Alloc al, A a)This works. Thank you. Good point about __ctor alone not being sufficient.auto memory = al.allocate(size);... <snip>GC.addRange(memory.ptr, size, typeid(CT));Nit: "GC.addRange..." -- this attempts to clean memory allocated manually.The problem is that the template make and emplace() are **elsewhere** so they cannot see A.this() (== A.__ctor). A common way to fix this kind of problem is to make a template mixin with the template that has the visibility and to mix it in the current scopeI guess this is the best workaround at the moment. There's a discontinuity between the GC and std.allocators. "new A(1)" works, because the GC has implicit private access to classes. I would love to see allocators in wider use. Workarounds are an obstacle to this. Possible solutions: * Emulate c++'s "friend" keyword somehow. D's rationale eschew's this. * Somehow designate friendship via [selective] module import? * Secret upcoming solution from Walter/Andrei. Weren't they discussing some sort of built in ref counting system?
May 01 2016
On Monday, 2 May 2016 at 04:19:48 UTC, earthfront wrote:On Sunday, 1 May 2016 at 19:18:38 UTC, Basile B wrote:Other solution: give "super powers" to the __traits()... used to inspect, like suggested in this bugzilla ticket: https://issues.dlang.org/show_bug.cgi?id=15371. The worst with this problem is that it's extremely easy to fix in the compiler source code. But it's extremely hard to make people understand that this is a real problem.CT make(CT, Alloc, A...)(auto ref Alloc al, A a)This works. Thank you. Good point about __ctor alone not being sufficient.auto memory = al.allocate(size);... <snip>GC.addRange(memory.ptr, size, typeid(CT));Nit: "GC.addRange..." -- this attempts to clean memory allocated manually.The problem is that the template make and emplace() are **elsewhere** so they cannot see A.this() (== A.__ctor). A common way to fix this kind of problem is to make a template mixin with the template that has the visibility and to mix it in the current scopeI guess this is the best workaround at the moment. There's a discontinuity between the GC and std.allocators. "new A(1)" works, because the GC has implicit private access to classes. I would love to see allocators in wider use. Workarounds are an obstacle to this. Possible solutions: * Emulate c++'s "friend" keyword somehow. D's rationale eschew's this. * Somehow designate friendship via [selective] module import? * Secret upcoming solution from Walter/Andrei. Weren't they discussing some sort of built in ref counting system?
May 01 2016