Re: How to call destructor before free without dropping @nogc?
On Thursday, 19 August 2021 at 15:38:19 UTC, evilrat wrote: On Thursday, 19 August 2021 at 15:12:03 UTC, Ferhat Kurtulmuş Btw, based on https://github.com/dlang/druntime/blob/master/src/object.d#L4209: import core.lifetime; import core.stdc.stdio; import core.stdc.stdlib; extern (C) void rt_finalize(void *data, bool det=true) @nogc nothrow; // cheap hack here alias destroy = rt_finalize; class SomeClass { int a = 42; this() @nogc { } ~this() @nogc {printf("nogc\n");} this(int val) @nogc { a = val; } } @nogc void main() { SomeClass dynAlloc = cast(SomeClass) malloc(__traits(classInstanceSize, SomeClass)); dynAlloc = emplace!SomeClass(dynAlloc, 123); printf("dynamic %d\n", dynAlloc.a); // 123 //rt_finalize(cast(void*)dynAlloc); destroy(cast(void*)dynAlloc); // cast needed :/ dunno consequences though }
Re: How to call destructor before free without dropping @nogc?
On Thursday, 19 August 2021 at 15:38:19 UTC, evilrat wrote: On Thursday, 19 August 2021 at 15:12:03 UTC, Ferhat Kurtulmuş This is cool, but even in unit tests for malloc wrapper there is only simple case with class without references to another class and no dtor. If you examine the entire library, there are various use cases of nogc classes. For instance, a derived class containing references to other class objects [1]. I am not using classes heavily with D. I just once happily used dplug's nogc facilities. When I saw this thread, I just wanted to share it here. Seems like the issue is that one have to add @nogc constructor/destructor overloads for emplace/destroy, and the author can't have @nogc dtor because of writeln (IIRC @nogc using GC is allowed with `debug` anyway), and all class members of another classes must recursively provide them as well. I agree with you. D needs more nogc facilities for OOP. It would not be so hard to include those overloads. Probably, this would violate the strictly defended safety principles of D? [1]: https://github.com/AuburnSounds/Dplug/blob/f67c14fd5ba44225d6669e87f942d641c8bf8ab8/window/dplug/window/cocoawindow.d
Re: How to call destructor before free without dropping @nogc?
On Thursday, 19 August 2021 at 09:39:26 UTC, evilrat wrote: On Thursday, 19 August 2021 at 08:25:23 UTC, Bienlein wrote: Oops, I just realized that you can also not call emplace when @nogc is present. Well that is at least consistent with not either being able to call destroy ;-). So, I guess this means that you can forget about manually allocating and freeing some instance of a class and using @nogc as well. That's a pitty, @nogc was a good idea. you are probably doing something wrong, could you try @nogc ctor? anyway @nogc is way too limiting, I don't see why bother when there is already `scope` storage (should work in nogc) and -vgc flag to show possible allocations. ```d import core.lifetime; import core.stdc.stdio; import core.stdc.stdlib; class SomeClass { int a = 42; this() @nogc { } this(int val) @nogc { a = val; } } @nogc void main() { byte[64] mem; mem.emplace!SomeClass(); printf("stack %d\n", (cast(SomeClass) mem.ptr).a); // 42 scope a = new SomeClass(); printf("scope %d\n", a.a); //42 SomeClass dynAlloc = cast(SomeClass) malloc(__traits(classInstanceSize, SomeClass)); dynAlloc = emplace!SomeClass(dynAlloc, 123); printf("dynamic %d\n", dynAlloc.a); // 123 } ``` Allocating to a function local variable via ```new``` always allocates on stack assuming no arguments are passed to new Read sentence 6 of https://dlang.org/spec/expression.html#new_expressions So ```d scope a = new SomeClass(); ``` actually allocates on stack
Re: How to call destructor before free without dropping @nogc?
On Thursday, 19 August 2021 at 15:12:03 UTC, Ferhat Kurtulmuş wrote: On Thursday, 19 August 2021 at 07:30:38 UTC, Bienlein wrote: Hello, I allocate some instance of class C manually and then free the memory again: [...] I just wanted to leave this here. https://github.com/AuburnSounds/Dplug/blob/master/core/dplug/core/nogc.d This is cool, but even in unit tests for malloc wrapper there is only simple case with class without references to another class and no dtor. Seems like the issue is that one have to add @nogc constructor/destructor overloads for emplace/destroy, and the author can't have @nogc dtor because of writeln (IIRC @nogc using GC is allowed with `debug` anyway), and all class members of another classes must recursively provide them as well.
Re: How to call destructor before free without dropping @nogc?
On Thursday, 19 August 2021 at 07:30:38 UTC, Bienlein wrote: Hello, I allocate some instance of class C manually and then free the memory again: [...] I just wanted to leave this here. https://github.com/AuburnSounds/Dplug/blob/master/core/dplug/core/nogc.d
Re: How to call destructor before free without dropping @nogc?
This works, vit. Thanks! I thought it wouldn't, because your code still makes use of embrace. But it somehow worked, although I don't understand why ... ;-). I also added a constructor using the same approach as your destructor and this also worked: this(int otherNum) @nogc { this.num = otherNum; debug writeln("this: ", this.num); } @evilrat: Will try what you suggested after work today. Too busy now.
Re: How to call destructor before free without dropping @nogc?
On Thursday, 19 August 2021 at 08:25:23 UTC, Bienlein wrote: Oops, I just realized that you can also not call emplace when @nogc is present. Well that is at least consistent with not either being able to call destroy ;-). So, I guess this means that you can forget about manually allocating and freeing some instance of a class and using @nogc as well. That's a pitty, @nogc was a good idea. you are probably doing something wrong, could you try @nogc ctor? anyway @nogc is way too limiting, I don't see why bother when there is already `scope` storage (should work in nogc) and -vgc flag to show possible allocations. ```d import core.lifetime; import core.stdc.stdio; import core.stdc.stdlib; class SomeClass { int a = 42; this() @nogc { } this(int val) @nogc { a = val; } } @nogc void main() { byte[64] mem; mem.emplace!SomeClass(); printf("stack %d\n", (cast(SomeClass) mem.ptr).a); // 42 scope a = new SomeClass(); printf("scope %d\n", a.a); //42 SomeClass dynAlloc = cast(SomeClass) malloc(__traits(classInstanceSize, SomeClass)); dynAlloc = emplace!SomeClass(dynAlloc, 123); printf("dynamic %d\n", dynAlloc.a); // 123 } ```
Re: How to call destructor before free without dropping @nogc?
On Thursday, 19 August 2021 at 08:25:23 UTC, Bienlein wrote: On Thursday, 19 August 2021 at 07:30:38 UTC, Bienlein wrote: Hello, I allocate some instance of class C manually and then free the memory again: class C { int num; ~this() { writeln("~this"); } } void foo() // @nogc { auto mem = cast(C)malloc(__traits(classInstanceSize, C)); auto c = emplace!(C)(mem); c.num = 789; destroy(c); free(cast(void*) c); c = null; } int main() { foo(); } The code above works well as the destructor of c in class C is called by destroy. Problem is that destroy cannot be used once function foo is annotated with @nogc. There seems to be no way round it. What I want is to keep the function foo annotated with @nogc, but still have the destructor of C be called before free is called. Is there a way to call the destructor through meta programming or some kind of reflection so that I can create some generic function that calls the destructor and then free for any kind of class? Thanks, Bienlein Oops, I just realized that you can also not call emplace when @nogc is present. Well that is at least consistent with not either being able to call destroy ;-). So, I guess this means that you can forget about manually allocating and freeing some instance of a class and using @nogc as well. That's a pitty, @nogc was a good idea. Try this: ```d import std; import core.stdc.stdlib : malloc, free; class C { int num; ~this() @nogc{ debug writeln("~this"); } } void foo() @nogc { auto mem = cast(C)malloc(__traits(classInstanceSize, C)); auto c = emplace!(C)(mem); c.num = 789; destruct(c); free(cast(void*) c); c = null; } void main() { foo(); } //https://github.com/atilaneves/automem/blob/master/source/automem/utils.d void destruct(T)(T obj) if (is(T == class)) { (cast(_finalizeType!T) &rt_finalize)(() @trusted { return cast(void*) obj; }()); } private extern(C){ void rt_finalize(void* p, bool det = true) @trusted @nogc pure nothrow; template _finalizeType(T) { import std.traits: Unqual; static if (is(Unqual!T == Object)) { alias _finalizeType = typeof(&rt_finalize); } else { import std.traits : BaseClassesTuple; import std.meta : AliasSeq; alias _finalizeType = typeof(function void(void* p, bool det = true) { // generate a body that calls all the destructors in the chain, // compiler should infer the intersection of attributes foreach (B; AliasSeq!(T, BaseClassesTuple!T)) { // __dtor, i.e. B.~this static if (__traits(hasMember, B, "__dtor")) () { B obj; obj.__dtor; } (); // __xdtor, i.e. dtors for all RAII members static if (__traits(hasMember, B, "__xdtor")) () { B obj; obj.__xdtor; } (); } }); } } } ```
Re: How to call destructor before free without dropping @nogc?
On Thursday, 19 August 2021 at 07:30:38 UTC, Bienlein wrote: Hello, I allocate some instance of class C manually and then free the memory again: class C { int num; ~this() { writeln("~this"); } } void foo() // @nogc { auto mem = cast(C)malloc(__traits(classInstanceSize, C)); auto c = emplace!(C)(mem); c.num = 789; destroy(c); free(cast(void*) c); c = null; } int main() { foo(); } The code above works well as the destructor of c in class C is called by destroy. Problem is that destroy cannot be used once function foo is annotated with @nogc. There seems to be no way round it. What I want is to keep the function foo annotated with @nogc, but still have the destructor of C be called before free is called. Is there a way to call the destructor through meta programming or some kind of reflection so that I can create some generic function that calls the destructor and then free for any kind of class? Thanks, Bienlein Oops, I just realized that you can also not call emplace when @nogc is present. Well that is at least consistent with not either being able to call destroy ;-). So, I guess this means that you can forget about manually allocating and freeing some instance of a class and using @nogc as well. That's a pitty, @nogc was a good idea.
How to call destructor before free without dropping @nogc?
Hello, I allocate some instance of class C manually and then free the memory again: class C { int num; ~this() { writeln("~this"); } } void foo() // @nogc { auto mem = cast(C)malloc(__traits(classInstanceSize, C)); auto c = emplace!(C)(mem); c.num = 789; destroy(c); free(cast(void*) c); c = null; } int main() { foo(); } The code above works well as the destructor of c in class C is called by destroy. Problem is that destroy cannot be used once function foo is annotated with @nogc. There seems to be no way round it. What I want is to keep the function foo annotated with @nogc, but still have the destructor of C be called before free is called. Is there a way to call the destructor through meta programming or some kind of reflection so that I can create some generic function that calls the destructor and then free for any kind of class? Thanks, Bienlein