www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - #dbugfix 17592

reply 12345swordy <alexanderheistermann gmail.com> writes:
This is very important to me as I am very interested in using the 
language for game development.

Yes I know that it's marked as "Duplicated", but I strongly 
disagree as it is different enough to consider is own issue.

Alex
Mar 20 2018
next sibling parent bauss <jj_1337 live.dk> writes:
On Tuesday, 20 March 2018 at 21:27:53 UTC, 12345swordy wrote:
 This is very important to me as I am very interested in using 
 the language for game development.

 Yes I know that it's marked as "Duplicated", but I strongly 
 disagree as it is different enough to consider is own issue.

 Alex
The game development part seems to be irrelevant, because D has been used to make plenty of games. It is however relevant to how your game would be developed, but your post make it seem like D can't be used to develop games at all.
Mar 21 2018
prev sibling next sibling parent Mike Parker <aldacron gmail.com> writes:
On Tuesday, 20 March 2018 at 21:27:53 UTC, 12345swordy wrote:
 This is very important to me as I am very interested in using 
 the language for game development.

 Yes I know that it's marked as "Duplicated", but I strongly 
 disagree as it is different enough to consider is own issue.

 Alex
Noted.
Mar 21 2018
prev sibling next sibling parent reply Mike Franklin <slavo5150 yahoo.com> writes:
On Tuesday, 20 March 2018 at 21:27:53 UTC, 12345swordy wrote:
 This is very important to me as I am very interested in using 
 the language for game development.

 Yes I know that it's marked as "Duplicated", but I strongly 
 disagree as it is different enough to consider is own issue.

 Alex
https://issues.dlang.org/show_bug.cgi?id=17592 Yeah that's pretty poopy. I looked into this and I think this is fixable. Here's my proof of concept: ----------------- import core.stdc.stdio; import std.traits; /******************************************************************* * This code was copied right out of druntime and * attributed with nogc *******************************************************************/ extern (C) void rt_finalize(void *data, bool det=true) nogc; void destroy(T)(T obj) nogc if (is(T == class)) { rt_finalize(cast(void*)obj); } /******************************************************************* * This emplace implementation below was copied * right out of std.conv and attributed with nogc *******************************************************************/ nogc pure nothrow safe void testEmplaceChunk(void[] chunk, size_t typeSize, size_t typeAlignment, string typeName) { assert(chunk.length >= typeSize, "emplace: Chunk size too small."); assert((cast(size_t) chunk.ptr) % typeAlignment == 0, "emplace: Chunk is not aligned."); } T emplace(T, Args...)(T chunk, auto ref Args args) nogc if (is(T == class)) { static assert(!isAbstractClass!T, T.stringof ~ " is abstract and it can't be emplaced"); // Initialize the object in its pre-ctor state enum classSize = __traits(classInstanceSize, T); (() trusted => (cast(void*) chunk)[0 .. classSize] = typeid(T).initializer[])(); static if (isInnerClass!T) { static assert(Args.length > 0, "Initializing an inner class requires a pointer to the outer class"); static assert(is(Args[0] : typeof(T.outer)), "The first argument must be a pointer to the outer class"); chunk.outer = args[0]; alias args1 = args[1..$]; } else alias args1 = args; // Call the ctor if any static if (is(typeof(chunk.__ctor(args1)))) { // T defines a genuine constructor accepting args // Go the classic route: write .init first, then call ctor chunk.__ctor(args1); } else { static assert(args1.length == 0 && !is(typeof(&T.__ctor)), "Don't know how to initialize an object of type " ~ T.stringof ~ " with arguments " ~ typeof(args1).stringof); } return chunk; } T emplace(T, Args...)(void[] chunk, auto ref Args args) nogc if (is(T == class)) { enum classSize = __traits(classInstanceSize, T); testEmplaceChunk(chunk, classSize, classInstanceAlignment!T, T.stringof); return emplace!T(cast(T)(chunk.ptr), args); } /******************************************************************* * This code was copied from https://wiki.dlang.org/Memory_Management#Explicit_Class_Instance_Allocation * and attributed with nogc *******************************************************************/ class TestClass { int x; this(int x) nogc { puts("TestClass's constructor called"); this.x = x; } ~this() nogc { puts("TestClass's destructor called"); } } T heapAllocate(T, Args...) (Args args) nogc { import core.stdc.stdlib : malloc; import core.memory : GC; // get class size of class instance in bytes auto size = __traits(classInstanceSize, T); // allocate memory for the object auto memory = malloc(size)[0..size]; if(!memory) { import core.exception : onOutOfMemoryError; onOutOfMemoryError(); } puts("Memory allocated"); // notify garbage collector that it should scan this memory GC.addRange(memory.ptr, size); // call T's constructor and emplace instance on // newly allocated memory return emplace!(T, Args)(memory, args); } void heapDeallocate(T)(T obj) nogc { import core.stdc.stdlib : free; import core.memory : GC; // calls obj's destructor destroy(obj); // garbage collector should no longer scan this memory GC.removeRange(cast(void*)obj); // free memory occupied by object free(cast(void*)obj); puts("Memory deallocated"); } void main() nogc { // allocate new instance of TestClass on the heap auto test = heapAllocate!TestClass(42); scope(exit) { heapDeallocate(test); } printf("test.x = %d\n", test.x); } ------------- Step 1. Make `emplace` nogc So we need to attribute `std.conv.emplace` as nogc. Based on the code above, that looks feasible. The difficulty, though will be writing thorough tests for it. Step 2. Make `destroy` nogc `destroy` simply calls `rt_finalize` in the runtime, at least for classes. I declared it as ` nogc` in the code above, but that's a cheat, though I think `rt_finalize` can be made ` nogc` in the runtime. I'll try to do step 2. If someone wants to help with step 1, that would be great. Mike
Mar 21 2018
next sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Wednesday, 21 March 2018 at 08:49:11 UTC, Mike Franklin wrote:

 I think `rt_finalize` can be made ` nogc` in the runtime.
And this is where you're wrong. Consider this: class A { nogc ~this() {} } class B : A { ~this() {} } A a = new B(); destroy(a); // Is this nogc? Essentially, since nogc and other qualifiers aren't inherited on dtors, it's impossible to know if destroying an instance of a non-final class is nogc. There's one case where you can: final classes where no superclass and no member defines a non- nogc destructor. In order for this to be done in the general case, dtors need to inherit their qualifiers somehow. That's at the very least a DIP, and any chosen path is highly likely to break existing code. -- Simen
Mar 21 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Wednesday, 21 March 2018 at 11:13:41 UTC, Simen Kjærås wrote:
 On Wednesday, 21 March 2018 at 08:49:11 UTC, Mike Franklin 
 wrote:

 I think `rt_finalize` can be made ` nogc` in the runtime.
And this is where you're wrong. Consider this: class A { nogc ~this() {} } class B : A { ~this() {} } A a = new B(); destroy(a); // Is this nogc? Essentially, since nogc and other qualifiers aren't inherited on dtors, it's impossible to know if destroying an instance of a non-final class is nogc. There's one case where you can: final classes where no superclass and no member defines a non- nogc destructor. In order for this to be done in the general case, dtors need to inherit their qualifiers somehow. That's at the very least a DIP, and any chosen path is highly likely to break existing code. -- Simen
You can simply check the .dtor symbols at compile time to see if every .dtor symbol from child to root have a .dtor that have the nogc attribute(and other attributes as well). If it does, add that attribute to destroy.
Mar 21 2018
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 21 March 2018 at 13:39:28 UTC, 12345swordy wrote:
 You can simply check the .dtor symbols at compile time to see 
 if every .dtor symbol from child to root have a .dtor that have 
 the  nogc attribute
In Simen's example, the child information is not available at compile time. This line here: A a = new B(); discards the static type. The compiler could probably cheat and figure it out anyway in this example, but suppose: --- class A { nogc ~this() {} } class B : A { ~this() {} } class C : A { nogc ~this() {} } A build(string name) { if(name == "B") return new B(); else return new C(); } void main() { A a = build(readln()); destroy(a); } --- This is very clearly a runtime decision: whether it is B or C is determined by user input. But B's dtor is not nogc... and there's thus no way to tell for sure if destroy(a) is or not, since it will call the child class based on the runtime decision. so it is impossible for the compiler to know which child class is actually called until runtime... too late for a compile-time nogc check.
Mar 21 2018
next sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Wednesday, 21 March 2018 at 14:04:58 UTC, Adam D. Ruppe wrote:
 On Wednesday, 21 March 2018 at 13:39:28 UTC, 12345swordy wrote:
 You can simply check the .dtor symbols at compile time to see 
 if every .dtor symbol from child to root have a .dtor that 
 have the  nogc attribute
In Simen's example, the child information is not available at compile time. This line here: A a = new B(); discards the static type. The compiler could probably cheat and figure it out anyway in this example, but suppose: --- class A { nogc ~this() {} } class B : A { ~this() {} } class C : A { nogc ~this() {} } A build(string name) { if(name == "B") return new B(); else return new C(); } void main() { A a = build(readln()); destroy(a); } --- This is very clearly a runtime decision: whether it is B or C is determined by user input. But B's dtor is not nogc... and there's thus no way to tell for sure if destroy(a) is or not, since it will call the child class based on the runtime decision. so it is impossible for the compiler to know which child class is actually called until runtime... too late for a compile-time nogc check.
That seems to be it's own separate problem, as it involves generating dynamic types at run-time, which it needs run-time equivalent of attribute checking. My example assumes that the classes created are static types not dynamic types. Besides I do not like implied conversions when it comes classes, as I believe it is a horrible idea.
Mar 21 2018
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 21 March 2018 at 19:21:15 UTC, 12345swordy wrote:
 That seems to be it's own separate problem, as it involves 
 generating dynamic types at run-time, which it needs run-time 
 equivalent of attribute checking.
But nogc is a compile time thing, meaning it cannot work here.
 My example assumes that the classes created are static types 
 not dynamic types. Besides I do not like implied conversions 
 when it comes classes, as I believe it is a horrible idea.
All classes are dynamic types, this is their reason for existing!
Mar 21 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Thursday, 22 March 2018 at 01:09:56 UTC, Adam D. Ruppe wrote:

 But  nogc is a compile time thing, meaning it cannot work here.
Are you suggesting that we need runtime version of system/user attributes?
 All classes are dynamic types
I do not see it anywhere in the dlang specification that supports your claim. https://dlang.org/spec/class.html Why can't it produce a warning message regarding implied classes conversion if it detects mismatch attributes? The risk of information exist when making certain dynamic type conversion. I do not see for any reason why they can't be warning messages regarding the possibility of losing information when making implied type conversions. There even a DIP pull request consist of deprecating a certain type conversion, because of certain bugs detected.
Mar 21 2018
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 22 March 2018 at 01:55:48 UTC, 12345swordy wrote:
 Are you suggesting that we need runtime version of system/user 
 attributes?
We already have that in a sense - InvalidMemoryOperationError is thrown if you try to GC allocate from inside a GC destructor. The attributes are supposed to render such runtime errors impossible, catching them at compile time instead.
 All classes are dynamic types
I do not see it anywhere in the dlang specification that supports your claim. https://dlang.org/spec/class.html
This is the reason why all D classes have a vtable attached (with attached runtime type info). *All* class-specific features are centered around this - casts use rtti, inheritance and interfaces use the vtable. It is the reason why D classes are reference types - otherwise, when you substitute it, you'd risk slicing the object. If you took the dynamic aspect out of classes, you'd have an entirely different animal... the thing D calls a "struct".
 Why can't it produce a warning message regarding implied 
 classes conversion if it detects mismatch attributes?
The entire purpose of OOP inheritance existing is the substitution principle, that subclasses can take the place of base classes transparently. This is an either-or situation: if we want to keep the current definition of classes, bug 17592 MUST be closed as "wontfix" as it is by design to maintain substitutiability. definition of class destructors to follow inheritance-style rules on matching attribute (even if they are actually implemented as a chain), again to guarantee substitutability is not broken. There's no middle ground possible.
Mar 21 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Thursday, 22 March 2018 at 02:35:41 UTC, Adam D. Ruppe wrote:
 On Thursday, 22 March 2018 at 01:55:48 UTC, 12345swordy wrote:
 Are you suggesting that we need runtime version of system/user 
 attributes?
We already have that in a sense - InvalidMemoryOperationError is thrown if you try to GC allocate from inside a GC destructor. The attributes are supposed to render such runtime errors impossible, catching them at compile time instead.
That is not a runtime version of system/user attributes! That is custom checking for destructor! Hardly the same.
 All classes are dynamic types
I do not see it anywhere in the dlang specification that supports your claim. https://dlang.org/spec/class.html
This is the reason why all D classes have a vtable attached (with attached runtime type info).
C++ classes also have vtables which are typically implemented as static arrays at compile time. Again I do not see it anywhere in the specification that support your claim that all classes are dynamic. Otherwise if what your saying is true then you should unable to use classes in Better C mode, as that involves runtime.
 Why can't it produce a warning message regarding implied 
 classes conversion if it detects mismatch attributes?
The entire purpose of OOP inheritance
I think you do not understand the question that I am asking. I am not asking to produce an ERROR message here, I am asking to produce a WARNING message here. We are dealing with the possibility of mismatch attributes, which seriously can cause some nasty bugs to leak, without the programmer noticing.
Mar 22 2018
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 22 March 2018 at 14:48:04 UTC, 12345swordy wrote:
 That is not a runtime version of system/user attributes! That 
 is custom checking for destructor! Hardly the same.
How would your idea work?
 Again I do not see it anywhere in the specification that 
 support your claim that all classes are dynamic. Otherwise if 
 what your saying is true then you should unable to use classes 
 in Better C mode, as that involves runtime.
Classes in fact do not work with -betterC. https://dlang.org/spec/betterc.html#consequences (Note that you CAN make D classes work with a minimal runtime though... but a runtime nonetheless.)
 I am asking to produce a WARNING message here.
Warning: your code is fundamentally broken and cannot work the way you want it to work.
Mar 22 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Thursday, 22 March 2018 at 17:02:43 UTC, Adam D. Ruppe wrote:
 On Thursday, 22 March 2018 at 14:48:04 UTC, 12345swordy wrote:
 That is not a runtime version of system/user attributes! That 
 is custom checking for destructor! Hardly the same.
How would your idea work?
I thought it was your idea.
 Classes in fact do not work with -betterC. 
 https://dlang.org/spec/betterc.html#consequences
"C++ classes and COM classes will still work" https://dlang.org/blog/2017/08/23/d-as-a-better-c/ A bit misleading in that statement. It should be "D Classes".
 Warning: your code is fundamentally broken and cannot work the 
 way you want it to work.
I can tell that you're being snarky at me.
Mar 22 2018
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Thursday, 22 March 2018 at 19:20:14 UTC, 12345swordy wrote:
 On Thursday, 22 March 2018 at 17:02:43 UTC, Adam D. Ruppe wrote:
 On Thursday, 22 March 2018 at 14:48:04 UTC, 12345swordy wrote:
 That is not a runtime version of system/user attributes! That 
 is custom checking for destructor! Hardly the same.
How would your idea work?
I thought it was your idea.
 Classes in fact do not work with -betterC. 
 https://dlang.org/spec/betterc.html#consequences
"C++ classes and COM classes will still work" https://dlang.org/blog/2017/08/23/d-as-a-better-c/ A bit misleading in that statement. It should be "D Classes".
No D classes requires D TypeInfo, not available in BetterC. It's well C++ classes ;)
 Warning: your code is fundamentally broken and cannot work the 
 way you want it to work.
I can tell that you're being snarky at me.
Mar 22 2018
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Thursday, 22 March 2018 at 19:21:57 UTC, Basile B. wrote:
 No D classes requires D TypeInfo, not available in BetterC.
 It's well C++ classes ;)
I was referring to the consequence section in the betterC article that he had linked.
Mar 22 2018
prev sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 22 March 2018 at 19:20:14 UTC, 12345swordy wrote:
 "C++ classes and COM classes will still work"
Because they have external runtimes that get used.
 I can tell that you're being snarky at me.
If you change .destroy without changing the destructor rule, the type system has been BROKEN. They MUST change together or all the "guarantees" are shot. A warning doesn't change this. The code is still broken.
Mar 22 2018
parent 12345swordy <alexanderheistermann gmail.com> writes:
On Thursday, 22 March 2018 at 19:52:43 UTC, Adam D Ruppe wrote:
 On Thursday, 22 March 2018 at 19:20:14 UTC, 12345swordy wrote:
 "C++ classes and COM classes will still work"
Because they have external runtimes that get used.
You are moving goal post here.
 I can tell that you're being snarky at me.
If you change .destroy without changing the destructor rule, the type system has been BROKEN. They MUST change together or all the "guarantees" are shot. A warning doesn't change this. The code is still broken.
Ok fine, I admit my solution have it's own set of problems. Still, the lack of nogc pure etc class deallocation is a severe issue for which is a major blocking point for me on creating video games without using the GC on the d language. I am certainly not going to resorting to hacking by forcing my custom dealloaction function for classes a nogc attribute as that undermines the verification aspect of the attribute.
Mar 22 2018
prev sibling parent Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Thursday, 22 March 2018 at 14:48:04 UTC, 12345swordy wrote:
 On Thursday, 22 March 2018 at 02:35:41 UTC, Adam D. Ruppe wrote:
 On Thursday, 22 March 2018 at 01:55:48 UTC, 12345swordy wrote:
 Are you suggesting that we need runtime version of 
 system/user attributes?
We already have that in a sense - InvalidMemoryOperationError is thrown if you try to GC allocate from inside a GC destructor. The attributes are supposed to render such runtime errors impossible, catching them at compile time instead.
That is not a runtime version of system/user attributes! That is custom checking for destructor! Hardly the same.
If I understand correctly, you envision a system where all or some GC operations would check the call stack to see if there are any nogc functions there (the implementation might be different, but that would be my conceptual design). This seems like a possible design, but one that pessimizes the happy path to the detriment of everyone.
 This is the reason why all D classes have a vtable attached 
 (with attached runtime type info).
C++ classes also have vtables which are typically implemented as static arrays at compile time. Again I do not see it anywhere in the specification that support your claim that all classes are dynamic. Otherwise if what your saying is true then you should unable to use classes in Better C mode, as that involves runtime.
Classes in D are dynamic in the same case that classes in C++, base class might actually point to a derived class, and there's no way to know at compile-time what's actually hiding behind that reference. That's how it's been meant all through this thread, but it seems a misunderstanding has crept in. In this case: class A {} class B : A {} A var = new B(); var's *static* type is A. That's what typeof(var) will return, and it's the type the compiler knows about. It's the type for which we can look at the destructor at compile-time and say 'we cannot do this in a nogc function'. On the other side, var's *dynamic* type is B. If instead of 'new B()', there was an opaque function call, it's impossible to know the dynamic type until run-time, and there's not even a point where we can give the warning message you suggest. -- Simen
Mar 22 2018
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 21 March 2018 at 14:04:58 UTC, Adam D. Ruppe wrote:
 In Simen's example, the child information is not available at 
 compile time. This line here:

 A a = new B();

 discards the static type. The compiler could probably cheat and 
 figure it out anyway in this example, but suppose:

 [snip]
There are a few interesting things in the class destructor part of the spec. For instance: "There can be only one destructor per class, the destructor does not have any parameters, and has no attributes. It is always virtual." If the destructor has no attributes, how can it be nogc? Also: "The destructor for the super class automatically gets called when the destructor ends. There is no way to call the super destructor explicitly." This means that you can't write something like below. Actually below gives the correct error. The problem is that if you remove the nogc on A, then the result is wonky (and no compile-time error) and if they both have nogc then you can't call destroy. import std.stdio : writeln; class A { nogc ~this() { writeln("destroy A"); } } class B : A { ~this() { writeln("destroy B"); destroy(super); } } void main() { A a = new B; }
Mar 22 2018
parent reply Basile B. <b2.temp gmx.com> writes:
On Thursday, 22 March 2018 at 20:25:28 UTC, jmh530 wrote:
 On Wednesday, 21 March 2018 at 14:04:58 UTC, Adam D. Ruppe 
 wrote:
 In Simen's example, the child information is not available at 
 compile time. This line here:

 A a = new B();

 discards the static type. The compiler could probably cheat 
 and figure it out anyway in this example, but suppose:

 [snip]
There are a few interesting things in the class destructor part of the spec. For instance: "There can be only one destructor per class, the destructor does not have any parameters, and has no attributes. It is always virtual."
Reality is very different. The __ctbl is NOT USED AT ALL to call the __dtor.
 If the destructor has no attributes, how can it be  nogc?

 Also:
 "The destructor for the super class automatically gets called 
 when the destructor ends. There is no way to call the super 
 destructor explicitly."
Reality is different. One can play with the __dtor member. This is what i do in IZ. - `destruct!(MyDerived)(myDerived)`: this has for effect to trust the static type that's passed to destruct(). That way destruct can be really nogc. - `destruct!(Object)(cast(Object)myDerived)`: this has for effect to use the dunamic type (i.e with typeid() i get the type info that contains a pointer to the __dtor, which CANT be nogc. This is equivalent to official destroy(). In both case i also use a mixin called `inheritedDtor` which, contrary to what is stated in the specs, allowd to call explicitly the super __dtor. I don't say that's the solution. I think there's no solution. What i do is not clean. It only works with displine and inside a particular library. I'm gonna post a DUB script as POC later.
Mar 22 2018
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 22 March 2018 at 21:37:40 UTC, Basile B. wrote:
 [snip]

 I don't say that's the solution. I think there's no solution.
I'm not sure there's no solution, but there's definitely no EASY solution. And when I say solution, I don't mean a resolution of this specific issue. I mean to resolve the fundamental issue, which is being able to clean up memory in betterC or nogc. There was a discussion last year [1] about adding destructors. According to the spec, class destructors were deprecated in D2, though confusingly I can't write a void delete() {} function, only delete(void*) {}. The delete function (outside of a class) is deprecated in 2.079 though. I'd guess that if deterministic destructors are added to the language, then this() and this() nogc inheritance becomes much less of an issue. [1]https://forum.dlang.org/thread/blbydqiupdtmgdunjzia forum.dlang.org?page=1
Mar 23 2018
parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Friday, 23 March 2018 at 18:40:45 UTC, jmh530 wrote:
 On Thursday, 22 March 2018 at 21:37:40 UTC, Basile B. wrote:
 [snip]

 I don't say that's the solution. I think there's no solution.
I'm not sure there's no solution, but there's definitely no EASY solution. And when I say solution, I don't mean a resolution of this specific issue. I mean to resolve the fundamental issue, which is being able to clean up memory in betterC or nogc.
Can we create new type of classes that combines system attributes with classes? Creating new keywords like nogcclass, safeclass by doing this. Which, take nogcclass for example, automatically adds nogc attribute to every function including .objects functions, which can not be removed. That way we avoid breaking backwards compatibility with the usage of default class by introducing new strict subset of classes. I am thinking writing a dip that goes into detail.
Mar 23 2018
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, March 23, 2018 21:45:14 12345swordy via Digitalmars-d wrote:
 On Friday, 23 March 2018 at 18:40:45 UTC, jmh530 wrote:
 On Thursday, 22 March 2018 at 21:37:40 UTC, Basile B. wrote:
 [snip]

 I don't say that's the solution. I think there's no solution.
I'm not sure there's no solution, but there's definitely no EASY solution. And when I say solution, I don't mean a resolution of this specific issue. I mean to resolve the fundamental issue, which is being able to clean up memory in betterC or nogc.
Can we create new type of classes that combines system attributes with classes? Creating new keywords like nogcclass, safeclass by doing this. Which, take nogcclass for example, automatically adds nogc attribute to every function including .objects functions, which can not be removed. That way we avoid breaking backwards compatibility with the usage of default class by introducing new strict subset of classes. I am thinking writing a dip that goes into detail.
Walter and Andrei have been discussing putting together a DIP with a "ProtoObject" which will be the new root class below Object where ProtoObject itself has only the bare minimum required to work as a class (not monitor object, no toString, no opEquals, etc.). Classes could then derive from ProtoObject directly instead of from Object, and then they could define any of the functions that are currently on Object with whatever attributes they wanted (or not define them at all). The DIP has not yet been written, and the details still need to be ironed out, but that's the gist of the direction that's currently being considered. - Jonathan M Davis
Mar 23 2018
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 23 March 2018 at 21:55:52 UTC, Jonathan M Davis wrote:
 [snip]

 Walter and Andrei have been discussing putting together a DIP 
 with a "ProtoObject" which will be the new root class below 
 Object where ProtoObject itself has only the bare minimum 
 required to work as a class (not monitor object, no toString, 
 no opEquals, etc.). Classes could then derive from ProtoObject 
 directly instead of from Object, and then they could define any 
 of the functions that are currently on Object with whatever 
 attributes they wanted (or not define them at all). The DIP has 
 not yet been written, and the details still need to be ironed 
 out, but that's the gist of the direction that's currently 
 being considered.

 - Jonathan M Davis
Object would derive from ProtoObject, right?
Mar 23 2018
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, March 23, 2018 22:33:53 jmh530 via Digitalmars-d wrote:
 On Friday, 23 March 2018 at 21:55:52 UTC, Jonathan M Davis wrote:
 [snip]

 Walter and Andrei have been discussing putting together a DIP
 with a "ProtoObject" which will be the new root class below
 Object where ProtoObject itself has only the bare minimum
 required to work as a class (not monitor object, no toString,
 no opEquals, etc.). Classes could then derive from ProtoObject
 directly instead of from Object, and then they could define any
 of the functions that are currently on Object with whatever
 attributes they wanted (or not define them at all). The DIP has
 not yet been written, and the details still need to be ironed
 out, but that's the gist of the direction that's currently
 being considered.

 - Jonathan M Davis
Object would derive from ProtoObject, right?
That would be the idea. That way, if all goes well, no code would break, and hopefully, over time, Object would be treated as legacy and phased out of use (though Andrei has stated that it's not his plan that Object actually be deprecated). Newer code would derive from ProtoObject rather than Object, and we'd have the flexibility with the functions that come from Object that we've wanted for years, because then they can be defined as appropriate by sub-classes of ProtoObject. - Jonathan M Davis
Mar 23 2018
prev sibling parent reply 12345swordy <alexanderheistermann gmail.com> writes:
On Friday, 23 March 2018 at 21:55:52 UTC, Jonathan M Davis wrote:
 On Friday, March 23, 2018 21:45:14 12345swordy via 
 Digitalmars-d wrote:
 [...]
Walter and Andrei have been discussing putting together a DIP with a "ProtoObject" which will be the new root class below Object where ProtoObject itself has only the bare minimum required to work as a class (not monitor object, no toString, no opEquals, etc.). Classes could then derive from ProtoObject directly instead of from Object, and then they could define any of the functions that are currently on Object with whatever attributes they wanted (or not define them at all). The DIP has not yet been written, and the details still need to be ironed out, but that's the gist of the direction that's currently being considered. - Jonathan M Davis
That what I have read from github. However the disadvantage of this is that you can not longer make assumptions of what default methods that they support.
Mar 23 2018
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Mar 23, 2018 at 10:40:36PM +0000, 12345swordy via Digitalmars-d wrote:
 On Friday, 23 March 2018 at 21:55:52 UTC, Jonathan M Davis wrote:
 On Friday, March 23, 2018 21:45:14 12345swordy via Digitalmars-d wrote:
 [...]
Walter and Andrei have been discussing putting together a DIP with a "ProtoObject" which will be the new root class below Object where ProtoObject itself has only the bare minimum required to work as a class (not monitor object, no toString, no opEquals, etc.). Classes could then derive from ProtoObject directly instead of from Object, and then they could define any of the functions that are currently on Object with whatever attributes they wanted (or not define them at all). The DIP has not yet been written, and the details still need to be ironed out, but that's the gist of the direction that's currently being considered. - Jonathan M Davis
That what I have read from github. However the disadvantage of this is that you can not longer make assumptions of what default methods that they support.
I don't think that's a problem. I presume the default would still be to inherit from Object when the class declaration doesn't explicitly specify ProtoObject. The assumption that any Object has toString, etc., would still hold for all existing code. ProtoObject would (almost) be like a separate hierarchy altogether. The only potential problem I can see is that some code that used to test for `is(T == class)` may now have to be changed to `is(T : Object)` if the purpose of the test was to check whether Object methods like toString, etc., are available. T -- Gone Chopin. Bach in a minuet.
Mar 23 2018
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, March 23, 2018 16:18:14 H. S. Teoh via Digitalmars-d wrote:
 On Fri, Mar 23, 2018 at 10:40:36PM +0000, 12345swordy via Digitalmars-d 
wrote:
 On Friday, 23 March 2018 at 21:55:52 UTC, Jonathan M Davis wrote:
 On Friday, March 23, 2018 21:45:14 12345swordy via Digitalmars-d 
wrote:
 [...]
Walter and Andrei have been discussing putting together a DIP with a "ProtoObject" which will be the new root class below Object where ProtoObject itself has only the bare minimum required to work as a class (not monitor object, no toString, no opEquals, etc.). Classes could then derive from ProtoObject directly instead of from Object, and then they could define any of the functions that are currently on Object with whatever attributes they wanted (or not define them at all). The DIP has not yet been written, and the details still need to be ironed out, but that's the gist of the direction that's currently being considered. - Jonathan M Davis
That what I have read from github. However the disadvantage of this is that you can not longer make assumptions of what default methods that they support.
I don't think that's a problem. I presume the default would still be to inherit from Object when the class declaration doesn't explicitly specify ProtoObject. The assumption that any Object has toString, etc., would still hold for all existing code. ProtoObject would (almost) be like a separate hierarchy altogether.
Yeah. The fact that Object has those functions has been a huge liability, and with templates, it's completely unnecessary to have them on Object for stuff like containers to work. Any code that needed to depend on a particular set of functions in a base class would need to use whatever that base class was, but then each code base could define that hierarchy base on what made sense for it rather than forcing one set of attributes on the entire language. Existing code that used Object in that fashion would continue to work.
 The only potential problem I can see is that some code that used to test
 for `is(T == class)` may now have to be changed to `is(T : Object)` if
 the purpose of the test was to check whether Object methods like
 toString, etc., are available.
Presumably, that will have to be covered as part of the DIP. I don't know how big a risk such issues pose, but they will have to be explored. Overall though, if we go with something like ProtoObject, it will solve a lot of the problems that we've had with Object. Several years ago, we decided that the various functions on Object should be removed, because they were causing too much trouble, but for various reasons, that's never happened even though it was agreed that that was the best way to go. ProtoObject would essentially be a way to go that route without actually breaking Object. Regardless, remember that nothing here is definitive yet. ProtoObject is just the direction that Andrei would like to take things, and Walter has agreed that we should have a DIP that explores the options appropriately. The details are still very much in flux. So, we'll have to wait and see, but I think that this is a promising turn of events. - Jonathan M Davis
Mar 23 2018
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Mar 23, 2018 at 03:55:52PM -0600, Jonathan M Davis via Digitalmars-d
wrote:
[...]
 Walter and Andrei have been discussing putting together a DIP with a
 "ProtoObject" which will be the new root class below Object where
 ProtoObject itself has only the bare minimum required to work as a
 class (not monitor object, no toString, no opEquals, etc.). Classes
 could then derive from ProtoObject directly instead of from Object,
 and then they could define any of the functions that are currently on
 Object with whatever attributes they wanted (or not define them at
 all).
Woo! Now *this* is good news indeed! A lot of my current code that uses classes would actually benefit from inheriting directly from ProtoObject as opposed to Object, since I don't need the monitor object, and don't really need a unified toString/opEquals/etc., either, since if they are needed for a particular class hierarchy I'd just declare them (with the right attributes!) in the base class. So they can be pure, nogc, whatever, without worrying about conflicts with the current definition of Object.
 The DIP has not yet been written, and the details still need to be
 ironed out, but that's the gist of the direction that's currently
 being considered.
[...] *This* is going to be a DIP I look forward to! T -- What do you get if you drop a piano down a mineshaft? A flat minor.
Mar 23 2018
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 21 March 2018 at 08:49:11 UTC, Mike Franklin wrote:
 Step 1.  Make `emplace`  nogc
 So we need to attribute `std.conv.emplace` as  nogc.
No, do not do that! `emplace` is ALREADY ` nogc` when given appropriate arguments. Adding the explicit annotation will limit its flexibility without enabling any new uses. This compiles right now: --- import std.conv; class Foo { this() nogc {} } nogc void main() { char[__traits(classInstanceSize, Foo)] buffer; emplace!Foo(buffer[]); } --- `emplace` is ` nogc` if the constructor it calls is ` nogc`. The real bug with nogc and things like emplace are the error messages. They should tell you the item in the call chain where nogc is NOT inferred. So if the ctor there was not annotated right now it says: Error: nogc function D main cannot call non- nogc function std.conv.emplace!(Foo).emplace Well, it should say: Error: nogc function D main cannot call non- nogc function std.conv.emplace!(Foo).emplace >> emplace was not inferred because it calls non- nogc function `Foo.this()` That supplemental bit with the >> indicates the ACTUAL reason nogc failed. Change that and the rest of the call tree becomes nogc automatically. I seem to remember filing this to bugzilla sometime but bugzilla search is so unbelievably bad I can never find anything on there so idk for sure. It'd keep others from chasing false leads.
 Step 2. Make `destroy`  nogc
 `destroy` simply calls `rt_finalize` in the runtime, at least 
 for classes.  I declared it as ` nogc` in the code above, but 
 that's a cheat, though I think `rt_finalize` can be made 
 ` nogc` in the runtime.
This cannot be proven at compile time since it calls destructors based on a dynamic type which may or may not keep the nogc promise. Of course, dtors that gc allocate are usually broken anyway... but it isn't a compile time guarantee in the current language and a library change cannot fix that alone.
Mar 21 2018
parent reply SimonN <eiderdaus gmail.com> writes:
On Wednesday, 21 March 2018 at 13:55:16 UTC, Adam D. Ruppe wrote:
`emplace` is ALREADY ` nogc`

Interesting -- I checked the phobos source, and none of the 
`emplace` or `emplaceRef` are declared ` nogc`, yet the unittests 
marked as ` nogc` pass.

Does the compiler infer nogc-ness of `emplace` at instantiation?

 class A {  nogc ~this() {} }
 class B : A { ~this() {} }
My first hunch was that B's yes-gc-destructor should be illegal when A's descructor is ` nogc`, but it can be legal because destructors in a hierarchy are chained, not overridden. Seems like there is no way to ensure at child-class-compile-time that all child classes of A must be designed ` nogc`. -- Simon
Mar 21 2018
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 22 March 2018 at 02:16:56 UTC, SimonN wrote:
 Does the compiler infer nogc-ness of `emplace` at instantiation?
Yes, it does with all templates, actually. Since their nogcness (and other attributes like nothrow, pure, etc) frequently depend on what arguments they are passed, the compiler will infer it at instantiation. Putting the explicit attribute on a template forces it to be such - then it will reject non-matching arguments (e.g. nogc emplace would be a compile error if passed a gc constructor, regardless of if it is used in a gc or nogc context. without the explicit attribute, the compiler infers it and thus only throws the error if used in an actual nogc context).
 My first hunch was that B's yes-gc-destructor should be illegal 
 when A's descructor is ` nogc`, but it can be legal because 
 destructors in a hierarchy are chained, not overridden. Seems 
 like there is no way to ensure at child-class-compile-time that 
 all child classes of A must be designed ` nogc`.
Right. That's the key problem to nogc destroy and why we can't fix it in the library - it would require a language chance to force subclass dtors to have the same attribute set as the base class, as if they were overridden virtual inherited members.
Mar 21 2018
prev sibling parent Basile B. <b2.temp gmx.com> writes:
On Tuesday, 20 March 2018 at 21:27:53 UTC, 12345swordy wrote:
 This is very important to me as I am very interested in using 
 the language for game development.

 Yes I know that it's marked as "Duplicated", but I strongly 
 disagree as it is different enough to consider is own issue.

 Alex
Here's something you can study. It's the only solution i've found so far and it's implemented in my user library called "IZ" (https://github.com/BBasile/iz). You can run the stuff simply by passing it as a file name to DUB (aka single file package): ``` /+dub.sdl: name "destruct_demo" dependency "iz" version="*" +/ module runnable; import std.stdio, iz.memory, iz.enumset; enum Foo {f1,f2,f3} alias SetOfFoo = EnumSet!(Foo,Set8); SetOfFoo foos; class Foo1 { this() nogc {foos = 0;} mixin inheritedDtor; ~this() nogc { foos.include(Foo.f1); callInheritedDtor(); } } class Foo2 : Foo1 { mixin inheritedDtor; ~this() nogc { foos.include(Foo.f2); callInheritedDtor(); } } class Foo3 : Foo2 { mixin inheritedDtor; ~this() nogc { foos.include(Foo.f3); callInheritedDtor(); } } void testTrustedStaticType() nogc { Foo1 f1 = construct!Foo3; assert(foos.none); destruct(f1); // destruct trusts f1 static type, which is wrong // with a dynamic destruct() we should get [Foo.f1, Foo.f2, Foo.f3] assert(foos == SetOfFoo(Foo.f1)); Foo3 f3 = construct!Foo3; assert(foos.none); destruct(f3); // destruct trusts f3 static type, which is right assert(foos == SetOfFoo(Foo.f1, Foo.f2, Foo.f3)); } void testDynamicType() // cant be nogc { Foo1 f1 = construct!Foo3; assert(foos.none); destruct(cast(Object) f1); // an Object is passed to "destruct" which means "detect dynamic type" assert(foos == [Foo.f1, Foo.f2, Foo.f3]); Foo1 f2 = construct!Foo3; assert(foos.none); destruct(cast(Object) f2); // an Object is passed to "destruct" which means "detect dynamic type" assert(foos == [Foo.f1, Foo.f2, Foo.f3]); } void main() { testTrustedStaticType(); testDynamicType(); } ``` Important points: - not compatible with D runtime - use mixins to overcome the fact that destructor are not virtual (it's a lie) - to be nogc, the static type has to be known, really.
Mar 22 2018