www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - GC for noobs

reply "Szymon Gatner" <noemail gmail.com> writes:
Hi,

I am evaluating D for future projects and coming from C++ I find 
it really hard to understand semantics of destruction of 
GC-managed code.

After many application-shutdown crashes caused by invalid order 
of class destructor calls I really think I need to change the way 
I am thinking about them (and resource management in general I 
suppose).

My crashes (still have them and can't track all as debugging D 
sucks) are caused by the fact that d-tor of parent object can be 
called before child d-tors. Adding destroy() calls in parent 
d-tors helped with some of crashes but I really hate this 
solution as I was virtually NEVER using 'delete' in C++.

I feel like I should be doing things in D very differently than I 
am doing them in C++. I now think I should be using structs 
everywhere because I understand them but I do need reference 
semantics (ideally with unique ownership).

Please point me to a literature for C++ programmer that has very 
little experience with GC/resource management, because at this 
point I really feel like GC should be easing things and working 
against me.
Feb 27 2014
parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
On Thursday, 27 February 2014 at 09:49:08 UTC, Szymon Gatner 
wrote:
 My crashes (still have them and can't track all as debugging D 
 sucks) are caused by the fact that d-tor of parent object can 
 be called before child d-tors. Adding destroy() calls in parent 
 d-tors helped with some of crashes but I really hate this 
 solution as I was virtually NEVER using 'delete' in C++.
Parent in the sense of an inheritance hierarchy or in the sense of a successor relation in a graph of objects? In the latter case the order of destruction is undefined (IMO), i.e. if you have class A { B someB; } where B is a class as well, than B might be already destroyed if A's destructor is run.
Feb 27 2014
parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
On Thursday, 27 February 2014 at 09:55:14 UTC, Tobias Pankrath 
wrote:
 On Thursday, 27 February 2014 at 09:49:08 UTC, Szymon Gatner 
 wrote:
 My crashes (still have them and can't track all as debugging D 
 sucks) are caused by the fact that d-tor of parent object can 
 be called before child d-tors. Adding destroy() calls in 
 parent d-tors helped with some of crashes but I really hate 
 this solution as I was virtually NEVER using 'delete' in C++.
Spec says: -- The garbage collector is not guaranteed to run the destructor for all unreferenced objects. Furthermore, the order in which the garbage collector calls destructors for unreference objects is not specified. This means that when the garbage collector calls a destructor for an object of a class that has members that are references to garbage collected objects, those references may no longer be valid. >> This means that destructors cannot reference sub objects. << --
Feb 27 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 09:57:51 UTC, Tobias Pankrath 
wrote:
 On Thursday, 27 February 2014 at 09:55:14 UTC, Tobias Pankrath 
 wrote:
 On Thursday, 27 February 2014 at 09:49:08 UTC, Szymon Gatner 
 wrote:
 My crashes (still have them and can't track all as debugging 
 D sucks) are caused by the fact that d-tor of parent object 
 can be called before child d-tors. Adding destroy() calls in 
 parent d-tors helped with some of crashes but I really hate 
 this solution as I was virtually NEVER using 'delete' in C++.
Spec says: -- The garbage collector is not guaranteed to run the destructor for all unreferenced objects. Furthermore, the order in which the garbage collector calls destructors for unreference objects is not specified. This means that when the garbage collector calls a destructor for an object of a class that has members that are references to garbage collected objects, those references may no longer be valid. >> This means that destructors cannot reference sub objects. << --
Parent-child in the sense of object graph. I did read the spec when I started to notice crashes. I must say that it really terrified me to my very bones. I always though that higher-level memory management environments would give more and not less guarantees. Anyway, I really need to learn how to design the code for CG and undefined d-tor calls. Any pointers would be welcome.
Feb 27 2014
parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
Szymon Gatner wrote:
 Parent-child in the sense of object graph. I did read the spec 
 when I started to notice crashes. I must say that it really 
 terrified me to my very bones. I always though that 
 higher-level memory management environments would give more and 
 not less guarantees.

 Anyway, I really need to learn how to design the code for CG 
 and undefined d-tor calls. Any pointers would be welcome.
I think that will depend on your use case. Why do you need to refer to child objects in your destructor?
Feb 27 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 10:40:15 UTC, Tobias Pankrath 
wrote:
 Szymon Gatner wrote:
 Parent-child in the sense of object graph. I did read the spec 
 when I started to notice crashes. I must say that it really 
 terrified me to my very bones. I always though that 
 higher-level memory management environments would give more 
 and not less guarantees.

 Anyway, I really need to learn how to design the code for CG 
 and undefined d-tor calls. Any pointers would be welcome.
I think that will depend on your use case. Why do you need to refer to child objects in your destructor?
I don't need to refer to children, I just want them to do their cleanup first as they should. This is basic resource-management stuff, surely there has to be generic advice out there?
Feb 27 2014
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Szymon Gatner:

I just want them to do their cleanup first as they should.
Why? Perhaps if you explain what's behind your needs better, people can help better. Bye, bearophile
Feb 27 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 11:13:17 UTC, bearophile wrote:
 Szymon Gatner:

I just want them to do their cleanup first as they should.
Why? Perhaps if you explain what's behind your needs better, people can help better. Bye, bearophile
In my specific example I am creating OpenGL Renderer. Renderer class instance holds GLContext instance. After context creation GL objects are created like textures and vertex buffers. Those are Texture and VertexBuffer class instances too. It is critical that those child resources are freed before GL context is destroyed. Thing is, even tho Renderer keeps list of Textures , VertexBuffers and Context object, order of their destruction is completely undefined making Context d-tor called first and then child resources d-tors which ends in catastrophe. In C++ (which has a LOT of problems) this is a no-brainer. Order of d-tors is fully defined. Sub-objects are destroyed before parent d-tor is called so only thing to worry about is the order of definition of members. This is just an example but I would think that it is something rather important to have... What about child objects un-registering themselves in d-tors from a list that parent object holds and parent is destroyed first? What about asynchronous completion handler object that should notify some other object that it finished/not finished a job but a notifee is already destroyed because application is being shut-down? I honestly can't imagine how to reason about object graph lifetimes in GC world and I am sure I am missing something very basic. Probably a very different mindset.
Feb 27 2014
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 27 February 2014 at 12:25:49 UTC, Szymon Gatner 
wrote:
 On Thursday, 27 February 2014 at 11:13:17 UTC, bearophile wrote:
 Szymon Gatner:

I just want them to do their cleanup first as they should.
Why? Perhaps if you explain what's behind your needs better, people can help better. Bye, bearophile
In my specific example I am creating OpenGL Renderer. Renderer class instance holds GLContext instance. After context creation GL objects are created like textures and vertex buffers. Those are Texture and VertexBuffer class instances too. It is critical that those child resources are freed before GL context is destroyed. Thing is, even tho Renderer keeps list of Textures , VertexBuffers and Context object, order of their destruction is completely undefined making Context d-tor called first and then child resources d-tors which ends in catastrophe. In C++ (which has a LOT of problems) this is a no-brainer. Order of d-tors is fully defined. Sub-objects are destroyed before parent d-tor is called so only thing to worry about is the order of definition of members. This is just an example but I would think that it is something rather important to have... What about child objects un-registering themselves in d-tors from a list that parent object holds and parent is destroyed first? What about asynchronous completion handler object that should notify some other object that it finished/not finished a job but a notifee is already destroyed because application is being shut-down? I honestly can't imagine how to reason about object graph lifetimes in GC world and I am sure I am missing something very basic. Probably a very different mindset.
I had the same problem in Dgame. Therefore I use shared pointers (https://github.com/Dgame/Dgame/blob/master/Graphics/Surface.d#L90) or if I have to use classes, I use this: https://github.com/Dgame/Dgame/blob/master/Window/Window.d#L44 https://github.com/Dgame/Dgame/blob/master/Window/Window.d#L177 I put the instances in a module global array and the module dtor finalize the data.
Feb 27 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 12:32:36 UTC, Namespace wrote:
 On Thursday, 27 February 2014 at 12:25:49 UTC, Szymon Gatner 
 wrote:
 On Thursday, 27 February 2014 at 11:13:17 UTC, bearophile 
 wrote:
 Szymon Gatner:

I just want them to do their cleanup first as they should.
Why? Perhaps if you explain what's behind your needs better, people can help better. Bye, bearophile
In my specific example I am creating OpenGL Renderer. Renderer class instance holds GLContext instance. After context creation GL objects are created like textures and vertex buffers. Those are Texture and VertexBuffer class instances too. It is critical that those child resources are freed before GL context is destroyed. Thing is, even tho Renderer keeps list of Textures , VertexBuffers and Context object, order of their destruction is completely undefined making Context d-tor called first and then child resources d-tors which ends in catastrophe. In C++ (which has a LOT of problems) this is a no-brainer. Order of d-tors is fully defined. Sub-objects are destroyed before parent d-tor is called so only thing to worry about is the order of definition of members. This is just an example but I would think that it is something rather important to have... What about child objects un-registering themselves in d-tors from a list that parent object holds and parent is destroyed first? What about asynchronous completion handler object that should notify some other object that it finished/not finished a job but a notifee is already destroyed because application is being shut-down? I honestly can't imagine how to reason about object graph lifetimes in GC world and I am sure I am missing something very basic. Probably a very different mindset.
I had the same problem in Dgame. Therefore I use shared pointers (https://github.com/Dgame/Dgame/blob/master/Graphics/Surface.d#L90) or if I have to use classes, I use this: https://github.com/Dgame/Dgame/blob/master/Window/Window.d#L44 https://github.com/Dgame/Dgame/blob/master/Window/Window.d#L177 I put the instances in a module global array and the module dtor finalize the data.
Module d-tor() looks like a pretty good solution, thanks. shared_ptr tho... I was really hoping that I am moving away from it to a better place... Still, this feels like working around a language issue, if c-tor order is defined why d-tor isn't? I am ok with non-deterministic time of execution of d-tors/finalizers but not-having parent-child d-tor order defined? That is weird.
Feb 27 2014
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 27 February 2014 at 13:00:27 UTC, Szymon Gatner 
wrote:
 On Thursday, 27 February 2014 at 12:32:36 UTC, Namespace wrote:
 On Thursday, 27 February 2014 at 12:25:49 UTC, Szymon Gatner 
 wrote:
 On Thursday, 27 February 2014 at 11:13:17 UTC, bearophile 
 wrote:
 Szymon Gatner:

I just want them to do their cleanup first as they should.
Why? Perhaps if you explain what's behind your needs better, people can help better. Bye, bearophile
In my specific example I am creating OpenGL Renderer. Renderer class instance holds GLContext instance. After context creation GL objects are created like textures and vertex buffers. Those are Texture and VertexBuffer class instances too. It is critical that those child resources are freed before GL context is destroyed. Thing is, even tho Renderer keeps list of Textures , VertexBuffers and Context object, order of their destruction is completely undefined making Context d-tor called first and then child resources d-tors which ends in catastrophe. In C++ (which has a LOT of problems) this is a no-brainer. Order of d-tors is fully defined. Sub-objects are destroyed before parent d-tor is called so only thing to worry about is the order of definition of members. This is just an example but I would think that it is something rather important to have... What about child objects un-registering themselves in d-tors from a list that parent object holds and parent is destroyed first? What about asynchronous completion handler object that should notify some other object that it finished/not finished a job but a notifee is already destroyed because application is being shut-down? I honestly can't imagine how to reason about object graph lifetimes in GC world and I am sure I am missing something very basic. Probably a very different mindset.
I had the same problem in Dgame. Therefore I use shared pointers (https://github.com/Dgame/Dgame/blob/master/Graphics/Surface.d#L90) or if I have to use classes, I use this: https://github.com/Dgame/Dgame/blob/master/Window/Window.d#L44 https://github.com/Dgame/Dgame/blob/master/Window/Window.d#L177 I put the instances in a module global array and the module dtor finalize the data.
Module d-tor() looks like a pretty good solution, thanks. shared_ptr tho... I was really hoping that I am moving away from it to a better place... Still, this feels like working around a language issue, if c-tor order is defined why d-tor isn't? I am ok with non-deterministic time of execution of d-tors/finalizers but not-having parent-child d-tor order defined? That is weird.
I use this solution especially because I have to finalize the data before I call SDL_Quit. And therefore I cannot trust the non-deterministic execution of the Dtor.
Feb 27 2014
parent "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 13:04:17 UTC, Namespace wrote:
 I use this solution especially because I have to finalize the 
 data before I call SDL_Quit. And therefore I cannot trust the 
 non-deterministic execution of the Dtor.
I fully understand that ;) I will take a look at DGame too for sure. Atm now I am still learning D and its abilities to directly use C code.
Feb 27 2014
prev sibling parent Mike Parker <aldacron gmail.com> writes:
On 2/27/2014 10:00 PM, Szymon Gatner wrote:

 Still, this feels like working around a language issue, if c-tor order
 is defined why d-tor isn't? I am ok with non-deterministic time of
 execution of d-tors/finalizers but not-having parent-child d-tor order
 defined? That is weird.
I've never seen a garbage collected language where the GC guarantees order of destruction. There's probably a very good reason for it.
Feb 27 2014
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On 2/27/2014 9:25 PM, Szymon Gatner wrote:

 This is just an example but I would think that it is something rather
 important to have... What about child objects un-registering themselves
 in d-tors from a list that parent object holds and parent is destroyed
 first? What about asynchronous completion handler object that should
 notify some other object that it finished/not finished a job but a
 notifee is already destroyed because application is being shut-down? I
 honestly can't imagine how to reason about object graph lifetimes in GC
 world and I am sure I am missing something very basic. Probably a very
 different mindset.
Two simple rules I follow. #1 Never rely on class destructors for determinstic clean up #2 Never rely on class destructors for releasing system resources I tend to add two methods to classes that need to do any sort of set up and clean up: initialize and terminate. Then, at app exit, I make sure that the terminate methods are called either with scope(exit) or, if I want to log any exceptions that percolate up to main, try-catch-finally. Something like this: class TextureManager { private TexContainer _loadedTextures; public void initialize() {...} public void terminate() { foreach( tex; _loadedTextures[]) tex.terminate(); } } struct Game { disable this(); disable this( this ); private static TextureManager _texMan; public static void initialize() { _texMan = new TextureManager(); _texMan.initialize(); } public static void terminate() { _texMan.terminate(); } } void main() { scope( exit ) Game.terminate(); Game.initialize(); } In some parts of a system, for objects that tend to be short lived, I'll use structs with destructors for RAII. A good example of this is for vertex and fragment shaders. The shader programs are long-lived, so those are classes, but I always destroy the shader objects as soon as any programs that need them are built. So those are perfect candidates for the struct-based RAII approach. RAII is a convenient tool, but it's just that, a tool. One of the tradeoffs you have to make with D's GC is that you can't use RAII the same way you do in C++. You *can* use it with structs, but for classes you're going to have to put C++ out of your head.
Feb 27 2014
parent reply "Remo" <remo4d gmail.com> writes:
On Thursday, 27 February 2014 at 13:07:37 UTC, Mike Parker wrote:
 On 2/27/2014 9:25 PM, Szymon Gatner wrote:

 This is just an example but I would think that it is something 
 rather
 important to have... What about child objects un-registering 
 themselves
 in d-tors from a list that parent object holds and parent is 
 destroyed
 first? What about asynchronous completion handler object that 
 should
 notify some other object that it finished/not finished a job 
 but a
 notifee is already destroyed because application is being 
 shut-down? I
 honestly can't imagine how to reason about object graph 
 lifetimes in GC
 world and I am sure I am missing something very basic. 
 Probably a very
 different mindset.
Two simple rules I follow. #1 Never rely on class destructors for determinstic clean up #2 Never rely on class destructors for releasing system resources I tend to add two methods to classes that need to do any sort of set up and clean up: initialize and terminate. Then, at app exit, I make sure that the terminate methods are called either with scope(exit) or, if I want to log any exceptions that percolate up to main, try-catch-finally. Something like this: class TextureManager { private TexContainer _loadedTextures; public void initialize() {...} public void terminate() { foreach( tex; _loadedTextures[]) tex.terminate(); } } struct Game { disable this(); disable this( this ); private static TextureManager _texMan; public static void initialize() { _texMan = new TextureManager(); _texMan.initialize(); } public static void terminate() { _texMan.terminate(); } } void main() { scope( exit ) Game.terminate(); Game.initialize(); } In some parts of a system, for objects that tend to be short lived, I'll use structs with destructors for RAII. A good example of this is for vertex and fragment shaders. The shader programs are long-lived, so those are classes, but I always destroy the shader objects as soon as any programs that need them are built. So those are perfect candidates for the struct-based RAII approach. RAII is a convenient tool, but it's just that, a tool. One of the tradeoffs you have to make with D's GC is that you can't use RAII the same way you do in C++. You *can* use it with structs, but for classes you're going to have to put C++ out of your head.
Then the question is why not use structs all the time? After using D for a bit more as a week I come to the solution that looks like this. strict WasAClassInCpp { disable this(); //sadly we can not use ctor in D like in C++ :( disable this(this); //this is not a copy constructor, this is something called after all the data in the struct was copied... ~this(){ ... } //dtor, just like in C++ } So all my classes in C++ are ported to D structs. I was using class only to port abstract class from C++. Replacing it by inerface.
Feb 27 2014
parent reply "Dicebot" <public dicebot.lv> writes:
On Thursday, 27 February 2014 at 13:18:51 UTC, Remo wrote:
 Then the question is why not use structs all the time?
Key class feature is run-time polymorphism (via interfaces/inheritance). I tend to use structs for everything else in my personal code.
Feb 27 2014
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 27 February 2014 at 13:31:45 UTC, Dicebot wrote:
 On Thursday, 27 February 2014 at 13:18:51 UTC, Remo wrote:
 Then the question is why not use structs all the time?
Key class feature is run-time polymorphism (via interfaces/inheritance). I tend to use structs for everything else in my personal code.
Maybe we really should implement ARC classes... :)
Feb 27 2014
parent reply "Dicebot" <public dicebot.lv> writes:
On Thursday, 27 February 2014 at 13:44:11 UTC, Namespace wrote:
 On Thursday, 27 February 2014 at 13:31:45 UTC, Dicebot wrote:
 On Thursday, 27 February 2014 at 13:18:51 UTC, Remo wrote:
 Then the question is why not use structs all the time?
Key class feature is run-time polymorphism (via interfaces/inheritance). I tend to use structs for everything else in my personal code.
Maybe we really should implement ARC classes... :)
I don't see how it is relevant. I would not have used ARC classes either.
Feb 27 2014
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 27 February 2014 at 14:12:58 UTC, Dicebot wrote:
 On Thursday, 27 February 2014 at 13:44:11 UTC, Namespace wrote:
 On Thursday, 27 February 2014 at 13:31:45 UTC, Dicebot wrote:
 On Thursday, 27 February 2014 at 13:18:51 UTC, Remo wrote:
 Then the question is why not use structs all the time?
Key class feature is run-time polymorphism (via interfaces/inheritance). I tend to use structs for everything else in my personal code.
Maybe we really should implement ARC classes... :)
I don't see how it is relevant. I would not have used ARC classes either.
Why not? Overhead? No RAII support?
Feb 27 2014
parent reply "Dicebot" <public dicebot.lv> writes:
On Thursday, 27 February 2014 at 14:14:43 UTC, Namespace wrote:
 Why not? Overhead? No RAII support?
Simply no reason to use classes, structs have all features I need for cases when polymorphism is not necessary (95%+). Being value type is also convenient as it leaves more control to the programmer and RAII is nice cherry on top.
Feb 27 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 14:18:47 UTC, Dicebot wrote:
 On Thursday, 27 February 2014 at 14:14:43 UTC, Namespace wrote:
 Why not? Overhead? No RAII support?
Simply no reason to use classes, structs have all features I need for cases when polymorphism is not necessary (95%+). Being value type is also convenient as it leaves more control to the programmer and RAII is nice cherry on top.
They actually don't have all the necessary features in D afaiu. They do have value semantics but can't represent uniqueness because of missing move d-tor. For example in C++ I can create a function that returns a Texture class instance and be sure that it is the only one when receiving it (because copying is disabled). Then I can always safely release all resources related to this texture in objects d-tor. In D I can't use struct for this because I would get double-free in d-tor so a class instance has to be used instead.
Feb 27 2014
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Thursday, 27 February 2014 at 14:37:14 UTC, Szymon Gatner 
wrote:
 They actually don't have all the necessary features in D afaiu. 
 They do have value semantics but can't represent uniqueness 
 because of missing move d-tor.

 For example in C++ I can create a function that returns a 
 Texture class instance and be sure that it is the only one when 
 receiving it (because copying is disabled). Then I can always 
 safely release all resources related to this texture in objects 
 d-tor. In D I can't use struct for this because I would get 
 double-free in d-tor so a class instance has to be used instead.
You can disable postblit to make entity non-copyable: http://dlang.org/struct.html#StructPostblit
Feb 27 2014
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
There is also one complex and feature-reach implementation of 
uniqueness concept by Sonke Ludwig : 
https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/cor
/concurrency.d#L281 
(Isolated!T)

Priceless for message passing concurrency.
Feb 27 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 14:42:43 UTC, Dicebot wrote:
 There is also one complex and feature-reach implementation of 
 uniqueness concept by Sonke Ludwig : 
 https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/cor
/concurrency.d#L281 
 (Isolated!T)

 Priceless for message passing concurrency.
Tbh it only looks worse and worse to me :( Another example of code necessary to overcome language limitations.
Feb 27 2014
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 27 February 2014 at 14:52:00 UTC, Szymon Gatner 
wrote:
 On Thursday, 27 February 2014 at 14:42:43 UTC, Dicebot wrote:
 There is also one complex and feature-reach implementation of 
 uniqueness concept by Sonke Ludwig : 
 https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/cor
/concurrency.d#L281 
 (Isolated!T)

 Priceless for message passing concurrency.
Tbh it only looks worse and worse to me :( Another example of code necessary to overcome language limitations.
Do you know Rust? http://www.rust-lang.org/
Feb 27 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 14:56:22 UTC, Namespace wrote:
 On Thursday, 27 February 2014 at 14:52:00 UTC, Szymon Gatner 
 wrote:
 On Thursday, 27 February 2014 at 14:42:43 UTC, Dicebot wrote:
 There is also one complex and feature-reach implementation of 
 uniqueness concept by Sonke Ludwig : 
 https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/cor
/concurrency.d#L281 
 (Isolated!T)

 Priceless for message passing concurrency.
Tbh it only looks worse and worse to me :( Another example of code necessary to overcome language limitations.
Do you know Rust? http://www.rust-lang.org/
I do. Do you want me to go away? ;)
Feb 27 2014
next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 27 February 2014 at 15:09:39 UTC, Szymon Gatner 
wrote:
 On Thursday, 27 February 2014 at 14:56:22 UTC, Namespace wrote:
 On Thursday, 27 February 2014 at 14:52:00 UTC, Szymon Gatner 
 wrote:
 On Thursday, 27 February 2014 at 14:42:43 UTC, Dicebot wrote:
 There is also one complex and feature-reach implementation 
 of uniqueness concept by Sonke Ludwig : 
 https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/cor
/concurrency.d#L281 
 (Isolated!T)

 Priceless for message passing concurrency.
Tbh it only looks worse and worse to me :( Another example of code necessary to overcome language limitations.
Do you know Rust? http://www.rust-lang.org/
I do. Do you want me to go away? ;)
No ;) But maybe Rust has your needed features. ;) If you want to stay at D, you can use the shared and unique pointer of Dgame.Internal if you want.
Feb 27 2014
prev sibling parent "Remo" <remo4d gmail.com> writes:
On Thursday, 27 February 2014 at 15:09:39 UTC, Szymon Gatner 
wrote:
 On Thursday, 27 February 2014 at 14:56:22 UTC, Namespace wrote:
 On Thursday, 27 February 2014 at 14:52:00 UTC, Szymon Gatner 
 wrote:
 On Thursday, 27 February 2014 at 14:42:43 UTC, Dicebot wrote:
 There is also one complex and feature-reach implementation 
 of uniqueness concept by Sonke Ludwig : 
 https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/cor
/concurrency.d#L281 
 (Isolated!T)

 Priceless for message passing concurrency.
Tbh it only looks worse and worse to me :( Another example of code necessary to overcome language limitations.
Do you know Rust? http://www.rust-lang.org/
I do. Do you want me to go away? ;)
I have looked at Rust and Go but I still prefer D2 :) D2 CTFE, templates and mixin are great. Another advantage of D is the 'easy' porting from C and C++. But this problems with structs and classes... I am also missing Rvalue references (move semantics) from C++11.
Feb 27 2014
prev sibling next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Szymon Gatner:

 Tbh it only looks worse and worse to me :(
Perhaps for your use case it's better for you to stick with C++11? While I have written a good amount of D code (perhaps 200_000 lines or more), I still use Python a lot, etc. Bye, bearophile
Feb 27 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 14:58:50 UTC, bearophile wrote:
 Szymon Gatner:

 Tbh it only looks worse and worse to me :(
Perhaps for your use case it's better for you to stick with C++11? While I have written a good amount of D code (perhaps 200_000 lines or more), I still use Python a lot, etc.
For now I don'r really see alternative. Isn't resource a management a crucial part of everyday programming? Or is it really just me? I do use Python for simple tools and work mainly in C++11(ish as it is really just Microsoft's dialect). Thing is, I really want to use D. I want "Modern convenience", "Modeling power" and "Native efficiency". I want to feel like home wrt to syntax and at the same time I want for some problems to just go away. I think I am just not getting something being so deeply rooted in C++.
Feb 27 2014
parent reply "Remo" <remo4d gmail.com> writes:
On Thursday, 27 February 2014 at 15:15:06 UTC, Szymon Gatner 
wrote:
 On Thursday, 27 February 2014 at 14:58:50 UTC, bearophile wrote:
 Szymon Gatner:

 Tbh it only looks worse and worse to me :(
Perhaps for your use case it's better for you to stick with C++11? While I have written a good amount of D code (perhaps 200_000 lines or more), I still use Python a lot, etc.
For now I don'r really see alternative. Isn't resource a management a crucial part of everyday programming? Or is it really just me?
Resource management is important part, but part but not every language handles it the same way. Apparently some peoples prefers that the language do almost all of this by it self no mater how bad/slow it is.
 I do use Python for simple tools and work mainly in C++11(ish 
 as it is really just Microsoft's dialect).
What do you mean by Microsoft's dialect?
Feb 27 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 15:36:02 UTC, Remo wrote:
 What do you mean by Microsoft's dialect?
I mean half-implemented buggy version of C++11 in VC2012 ;)
Feb 27 2014
parent reply "Remo" <remo4d gmail.com> writes:
On Thursday, 27 February 2014 at 15:39:48 UTC, Szymon Gatner 
wrote:
 On Thursday, 27 February 2014 at 15:36:02 UTC, Remo wrote:
 What do you mean by Microsoft's dialect?
I mean half-implemented buggy version of C++11 in VC2012 ;)
Or in VC2013, but if you can use Intel compiler then it is better.
Feb 27 2014
parent "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 15:56:26 UTC, Remo wrote:
 On Thursday, 27 February 2014 at 15:39:48 UTC, Szymon Gatner 
 wrote:
 On Thursday, 27 February 2014 at 15:36:02 UTC, Remo wrote:
 What do you mean by Microsoft's dialect?
I mean half-implemented buggy version of C++11 in VC2012 ;)
Or in VC2013, but if you can use Intel compiler then it is better.
VC2013 at least has variadics... I will not spend another 400 bucks just for that tho, and only a year after previous release. But that is OT ;)
Feb 27 2014
prev sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 27 February 2014 at 14:52:00 UTC, Szymon Gatner 
wrote:
 On Thursday, 27 February 2014 at 14:42:43 UTC, Dicebot wrote:
 There is also one complex and feature-reach implementation of 
 uniqueness concept by Sonke Ludwig : 
 https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/cor
/concurrency.d#L281 
 (Isolated!T)

 Priceless for message passing concurrency.
Tbh it only looks worse and worse to me :( Another example of code necessary to overcome language limitations.
Or, alternatively: A language flexible enough to facilitate library solutions for problems that would normally require explicit language support.
Feb 27 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 18:06:58 UTC, John Colvin wrote:
 On Thursday, 27 February 2014 at 14:52:00 UTC, Szymon Gatner 
 wrote:
 On Thursday, 27 February 2014 at 14:42:43 UTC, Dicebot wrote:
 There is also one complex and feature-reach implementation of 
 uniqueness concept by Sonke Ludwig : 
 https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/cor
/concurrency.d#L281 
 (Isolated!T)

 Priceless for message passing concurrency.
Tbh it only looks worse and worse to me :( Another example of code necessary to overcome language limitations.
Or, alternatively: A language flexible enough to facilitate library solutions for problems that would normally require explicit language support.
I dig flexibility, I really do, and I appreciate D's features that enable that, but in case of such basic thing as a resource management, I just want things to work without surprises by default.
Feb 27 2014
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Thursday, 27 February 2014 at 18:29:57 UTC, Szymon Gatner 
wrote:
 I dig flexibility, I really do, and I appreciate D's features 
 that enable that, but in case of such basic thing as a resource 
 management, I just want things to work without surprises by 
 default.
Resource management (including memory management) is on of most complicated areas in programming. I can call it anything but basic.
Feb 28 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Friday, 28 February 2014 at 10:44:22 UTC, Dicebot wrote:
 On Thursday, 27 February 2014 at 18:29:57 UTC, Szymon Gatner 
 wrote:
 I dig flexibility, I really do, and I appreciate D's features 
 that enable that, but in case of such basic thing as a 
 resource management, I just want things to work without 
 surprises by default.
Resource management (including memory management) is on of most complicated areas in programming. I can call it anything but basic.
I didn't mean "basic" in the sense of "easy" but in the sense of something that has to dealt with all the time / is common requirement. "Programs == Algorithms + Data structures" great man once said. D is pretty damn good at algorithms part, better than C++ thanks to ranges (zero cost composability codegen issues aside) but data strucutres... I wish I felt the same way about them. Is it really so much to ask for? That child's finalizers are called before parent finalizer (assuming no circular refs, then again there are no weak class refst in D right)? Parent holds references to them for crying out loud... Why is that not the default and obvious behaviour? Is that a limitation imposed by GC somehow? My understanding is that GC has to scan from root to leaves so it knows the structure exactly anyway, why not just generate finalizer call list when traversing?
Feb 28 2014
parent reply "Dicebot" <public dicebot.lv> writes:
On Friday, 28 February 2014 at 11:28:01 UTC, Szymon Gatner wrote:
 I didn't mean "basic" in the sense of "easy" but in the sense 
 of something that has to dealt with all the time / is common 
 requirement.
Yes, it needs to be dealt with all the time but in a different ways. Problem is with getting sensible defaults. D makes a reasonable assumption that most applications don't actually care about tight bullet-proof resource management and defaults to GC. I may not like it but it fits criteria "built-in resource management" and pretty much shows that it is not as basic as one may think.
 "Programs == Algorithms + Data structures" great man once said. 
 D is pretty damn good at algorithms part, better than C++ 
 thanks to ranges (zero cost composability codegen issues aside) 
 but data strucutres... I wish I felt the same way about them.
Most problems I have with D data structures come from qualifiers, not from resource management. I really don't understand why this looks that much of a problem. That said, my background very influenced by plain C and that results in different habits and expectations.
 Is that a limitation imposed by GC somehow? My understanding is 
 that GC has to scan from root to leaves so it knows the 
 structure exactly anyway, why not just generate finalizer call 
 list when traversing?
Can't tell because of my very limited knowledge about GC internals. In practice I don't care because I never ever want to interfere with GC resource mangement - stuff that I want to micro-managed is allocated from custom pools and thus is not a subject to unexpected destructor calls.
Feb 28 2014
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On 2/28/2014 8:43 PM, Dicebot wrote:

 Most problems I have with D data structures come from qualifiers, not
 from resource management. I really don't understand why this looks that
 much of a problem. That said, my background very influenced by plain C
 and that results in different habits and expectations.
I have a strong C background as well and have never had any complaints about resource management in D. Every complaint I've seen has come from people trying to do C++-like RAII. And, though I don't understand it either, it does seem to be a big issue for them.
Feb 28 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Friday, 28 February 2014 at 11:54:52 UTC, Mike Parker wrote:
 On 2/28/2014 8:43 PM, Dicebot wrote:

 Most problems I have with D data structures come from 
 qualifiers, not
 from resource management. I really don't understand why this 
 looks that
 much of a problem. That said, my background very influenced by 
 plain C
 and that results in different habits and expectations.
I have a strong C background as well and have never had any complaints about resource management in D. Every complaint I've seen has come from people trying to do C++-like RAII. And, though I don't understand it either, it does seem to be a big issue for them.
It really is, RAII is the most important idiom in C++, in short no RAII == buggy code. I mean proper C++ not C-with-classes-no-templates-no-exceptions bs. So to sum up: C folks are not really happy, C++ folks are not really happy and C# folks are not really happy :P
Feb 28 2014
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Friday, 28 February 2014 at 12:15:21 UTC, Szymon Gatner wrote:
 It really is, RAII is the most important idiom in C++, in short 
 no RAII == buggy code. I mean proper C++ not 
 C-with-classes-no-templates-no-exceptions bs.

 So to sum up: C folks are not really happy, C++ folks are not 
 really happy and C# folks are not really happy :P
Repeating this again and again - you can use RAII. Just not with GC. It is importan idiom and it is supported. But it is not "one true way" so it is not supported for everything.
Feb 28 2014
parent "Szymon Gatner" <noemail gmail.com> writes:
On Friday, 28 February 2014 at 12:17:22 UTC, Dicebot wrote:
 On Friday, 28 February 2014 at 12:15:21 UTC, Szymon Gatner 
 wrote:
 It really is, RAII is the most important idiom in C++, in 
 short no RAII == buggy code. I mean proper C++ not 
 C-with-classes-no-templates-no-exceptions bs.

 So to sum up: C folks are not really happy, C++ folks are not 
 really happy and C# folks are not really happy :P
Repeating this again and again - you can use RAII. Just not with GC. It is importan idiom and it is supported. But it is not "one true way" so it is not supported for everything.
I know I can, my point is that it is more difficult and I don't like it ;)
Feb 28 2014
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On 2/28/2014 9:15 PM, Szymon Gatner wrote:

 So to sum up: C folks are not really happy, C++ folks are not really
 happy and C# folks are not really happy :P
I'm a C folk and I'm really happy :)
Feb 28 2014
parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Friday, 28 February 2014 at 12:48:47 UTC, Mike Parker wrote:
 On 2/28/2014 9:15 PM, Szymon Gatner wrote:

 So to sum up: C folks are not really happy, C++ folks are not 
 really
 happy and C# folks are not really happy :P
I'm a C folk and I'm really happy :)
C'mon, GC has to be an itch for you mallocers :) Come to the dark side...
Feb 28 2014
parent "Dicebot" <public dicebot.lv> writes:
On Friday, 28 February 2014 at 12:52:28 UTC, Szymon Gatner wrote:
 I'm a C folk and I'm really happy :)
+1
 C'mon, GC has to be an itch for you mallocers :)

 Come to the dark side...
It sometimes is. In that case we don't use GC. Don't get me wrong - there are issues with current GC enforcement and it is a major problem for real-time applications, there are lot of threads with debates on topic (with me acting on against-the-GC side). But it is a very small subset of applications most programmers will never even write once in their life, for everything else existing tools are pretty good. I really think it is more of C++ architectural habit that itches you right now :)
Feb 28 2014
prev sibling parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Friday, 28 February 2014 at 11:43:58 UTC, Dicebot wrote:
 On Friday, 28 February 2014 at 11:28:01 UTC, Szymon Gatner 
 wrote:
 I didn't mean "basic" in the sense of "easy" but in the sense 
 of something that has to dealt with all the time / is common 
 requirement.
Yes, it needs to be dealt with all the time but in a different ways. Problem is with getting sensible defaults. D makes a reasonable assumption that most applications don't actually care about tight bullet-proof resource management and defaults to GC. I may not like it but it fits criteria "built-in resource management" and pretty much shows that it is not as basic as one may think.
Not really different tho. Actual function call swqence might be different but the scheme is always the same: acquire resource, allocate, connect, take from pool vs release, deallocate, disconnect, return to pool. All of those fall under resource management - there is a finite amout of a resouce whether it is a memory, a system process, a file or a databese connection and it is crucial to the system stability that all of them are properly returned / released AND in proper order (which is of course reverse to "acquisition").
Feb 28 2014
parent Xavier Bigand <flamaros.xavier gmail.com> writes:
Le 28/02/2014 13:22, Szymon Gatner a écrit :
 On Friday, 28 February 2014 at 11:43:58 UTC, Dicebot wrote:
 On Friday, 28 February 2014 at 11:28:01 UTC, Szymon Gatner wrote:
 I didn't mean "basic" in the sense of "easy" but in the sense of
 something that has to dealt with all the time / is common requirement.
Yes, it needs to be dealt with all the time but in a different ways. Problem is with getting sensible defaults. D makes a reasonable assumption that most applications don't actually care about tight bullet-proof resource management and defaults to GC. I may not like it but it fits criteria "built-in resource management" and pretty much shows that it is not as basic as one may think.
Not really different tho. Actual function call swqence might be different but the scheme is always the same: acquire resource, allocate, connect, take from pool vs release, deallocate, disconnect, return to pool. All of those fall under resource management - there is a finite amout of a resouce whether it is a memory, a system process, a file or a databese connection and it is crucial to the system stability that all of them are properly returned / released AND in proper order (which is of course reverse to "acquisition").
I had a lot of difficulties too with the release order of resources. Of course I am coming from c++, in which it's to ease to manage. I got some head-hack for the resource management, maybe a DIP must be done here about a module dedicated to the resource management? Or at least a tutorial in the wiki? I finally solve my issues, but I am not happy, cause the way it's done seems to be too much error prone (resource leaks). I used to work on mobile devices and some kind of resources have to be released as soon as possible. I also don't really like having a lot of applications running on devices never releasing resources, it can break the principle of multi-task OS. Just try to launch many Java/C# applications at the same time, you'll have to buy more memory.
Feb 28 2014
prev sibling parent reply "Regan Heath" <regan netmail.co.nz> writes:
On Thu, 27 Feb 2014 18:29:55 -0000, Szymon Gatner <noemail gmail.com>  
wrote:

 On Thursday, 27 February 2014 at 18:06:58 UTC, John Colvin wrote:
 On Thursday, 27 February 2014 at 14:52:00 UTC, Szymon Gatner wrote:
 On Thursday, 27 February 2014 at 14:42:43 UTC, Dicebot wrote:
 There is also one complex and feature-reach implementation of  
 uniqueness concept by Sonke Ludwig :  
 https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/cor
/concurrency.d#L281  
 (Isolated!T)

 Priceless for message passing concurrency.
Tbh it only looks worse and worse to me :( Another example of code necessary to overcome language limitations.
Or, alternatively: A language flexible enough to facilitate library solutions for problems that would normally require explicit language support.
I dig flexibility, I really do, and I appreciate D's features that enable that, but in case of such basic thing as a resource management, I just want things to work without surprises by default.
Amen. (Not used religiously) I have been around D for a long time, and I have noticed a growing trend of solving problems with "clever" but complicated library solutions when in *some* cases a simpler built-in solution was possible. I realise Walter's time is precious and I realise that adding complexity to the language itself is something to be generally avoided, but I think sometimes we make the wrong choice. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Feb 28 2014
parent "Namespace" <rswhite4 googlemail.com> writes:
On Friday, 28 February 2014 at 10:45:53 UTC, Regan Heath wrote:
 On Thu, 27 Feb 2014 18:29:55 -0000, Szymon Gatner 
 <noemail gmail.com> wrote:

 On Thursday, 27 February 2014 at 18:06:58 UTC, John Colvin 
 wrote:
 On Thursday, 27 February 2014 at 14:52:00 UTC, Szymon Gatner 
 wrote:
 On Thursday, 27 February 2014 at 14:42:43 UTC, Dicebot wrote:
 There is also one complex and feature-reach implementation 
 of uniqueness concept by Sonke Ludwig : 
 https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/cor
/concurrency.d#L281 
 (Isolated!T)

 Priceless for message passing concurrency.
Tbh it only looks worse and worse to me :( Another example of code necessary to overcome language limitations.
Or, alternatively: A language flexible enough to facilitate library solutions for problems that would normally require explicit language support.
I dig flexibility, I really do, and I appreciate D's features that enable that, but in case of such basic thing as a resource management, I just want things to work without surprises by default.
Amen. (Not used religiously) I have been around D for a long time, and I have noticed a growing trend of solving problems with "clever" but complicated library solutions when in *some* cases a simpler built-in solution was possible. I realise Walter's time is precious and I realise that adding complexity to the language itself is something to be generally avoided, but I think sometimes we make the wrong choice. R
Yeah scope -> scoped is IMO such a wrong choice. :)
Feb 28 2014
prev sibling parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 14:41:27 UTC, Dicebot wrote:
 On Thursday, 27 February 2014 at 14:37:14 UTC, Szymon Gatner 
 wrote:
 They actually don't have all the necessary features in D 
 afaiu. They do have value semantics but can't represent 
 uniqueness because of missing move d-tor.

 For example in C++ I can create a function that returns a 
 Texture class instance and be sure that it is the only one 
 when receiving it (because copying is disabled). Then I can 
 always safely release all resources related to this texture in 
 objects d-tor. In D I can't use struct for this because I 
 would get double-free in d-tor so a class instance has to be 
 used instead.
You can disable postblit to make entity non-copyable: http://dlang.org/struct.html#StructPostblit
How can I then use it as a function return value? Or store in a container? Actually if postblit had a bool param saying that the source is rvalue then moving would be possible by just resetting relevant fields in source object.
Feb 27 2014
parent "Dicebot" <public dicebot.lv> writes:
On Thursday, 27 February 2014 at 14:49:48 UTC, Szymon Gatner 
wrote:
 You can disable postblit to make entity non-copyable: 
 http://dlang.org/struct.html#StructPostblit
How can I then use it as a function return value? Or store in a container? Actually if postblit had a bool param saying that the source is rvalue then moving would be possible by just resetting relevant fields in source object.
Yep, moving ownership is the main issue (as opposed to just prohibiting any copy). But returning from function is not copying because of D semantics and you can do some tricks because of it: http://dpaste.dzfl.pl/99ca668a1a8d ================================== import std.c.stdlib; struct Unique { int* data; disable this(this); ~this() { if (data) free(data); } Unique release() { scope(exit) this.data = null; return Unique(data); } } void main() { Unique x1 = Unique(cast(int*) malloc(int.sizeof)); // auto x2 = x1; // error auto x2 = x1.release(); assert(x1.data is null); assert(x2.data !is null); }
Feb 27 2014
prev sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 27 February 2014 at 14:37:14 UTC, Szymon Gatner 
wrote:
 They actually don't have all the necessary features in D afaiu. 
 They do have value semantics but can't represent uniqueness 
 because of missing move d-tor.
struct MovingStruct { disable this(this); typeof(this) release() { auto p = this.payload; this.payload = null; return typeof(this)(p); } } That does moving via an explicit release call which is statically forced upon you by the disabled copy. MovingStruct s = some_payload; // MovingStruct s2 = s; // compile error MovingStruct s2 = s.release; assert(s.payload is null); // passes assert(s2.payload is some_payload); // we good You can also easily do structs with reference semantics: struct RefStruct { private struct Impl { // implementation here } Impl* payload; alias payload this; } RefStruct is now just a thin wrapper over a pointer and thus inherits the pointer's semantics. You can add a destructor to RefStruct to free it deterministically with RAII as well. To avoid double free, you can use the move technique or refcounting: struct RefCountingStruct { private struct Impl { // implementation here int refcount; } Impl* payload; alias payload this; disable this(); // disable default constructor to force factory static RefCountingStruct create() { RefCountingStruct t = void; t.payload = new Impl(); t.payload.refcount = 1; return t; } this(this) { if(payload !is null) payload.refcount++; } ~this() { if(payload !is null) { payload.refcount--; if(payload.refcount == 0) whatever_free(payload); } } } i wish my book was out but it is still only half done... but i wrote a chapter with like eight different struct tricks like this. structs rock.
Feb 27 2014
next sibling parent "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 16:10:34 UTC, Adam D. Ruppe 
wrote:
 On Thursday, 27 February 2014 at 14:37:14 UTC, Szymon Gatner 
 wrote:
 They actually don't have all the necessary features in D 
 afaiu. They do have value semantics but can't represent 
 uniqueness because of missing move d-tor.
struct MovingStruct { disable this(this); typeof(this) release() { auto p = this.payload; this.payload = null; return typeof(this)(p); } } That does moving via an explicit release call which is statically forced upon you by the disabled copy. MovingStruct s = some_payload; // MovingStruct s2 = s; // compile error MovingStruct s2 = s.release; assert(s.payload is null); // passes assert(s2.payload is some_payload); // we good You can also easily do structs with reference semantics: struct RefStruct { private struct Impl { // implementation here } Impl* payload; alias payload this; } RefStruct is now just a thin wrapper over a pointer and thus inherits the pointer's semantics. You can add a destructor to RefStruct to free it deterministically with RAII as well. To avoid double free, you can use the move technique or refcounting: struct RefCountingStruct { private struct Impl { // implementation here int refcount; } Impl* payload; alias payload this; disable this(); // disable default constructor to force factory static RefCountingStruct create() { RefCountingStruct t = void; t.payload = new Impl(); t.payload.refcount = 1; return t; } this(this) { if(payload !is null) payload.refcount++; } ~this() { if(payload !is null) { payload.refcount--; if(payload.refcount == 0) whatever_free(payload); } } } i wish my book was out but it is still only half done... but i wrote a chapter with like eight different struct tricks like this. structs rock.
Wow, that is pretty great stuff. Bit verbose, but gets the job done. Is there a way to factor it out for reuse? As a mixin probably? Thanks! Will surely try this. And I want your book.
Feb 27 2014
prev sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Thursday, 27 February 2014 at 16:10:34 UTC, Adam D. Ruppe 
wrote:
 struct RefCountingStruct {
     private struct Impl {
       // implementation here

       int refcount;
     }
     Impl* payload;
     alias payload this;
Isn't it exactly what Phobos RefCounted does?
Feb 27 2014
parent "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 27 February 2014 at 17:31:57 UTC, Dicebot wrote:
 Isn't it exactly what Phobos RefCounted does?
Yes, though knowing how the implementation works is good for stuff like interfacing with C where you might need different acquire/free/add count/release functions than phobos uses. http://dlang.org/phobos/std_typecons.html#RefCounted It always uses malloc and free, which isn't always (actually, in my cases, is rarely ever) what you want. It is (obviously) possible to write a generic one that takes aliases (or delegates if you want all refcounted things to have the same parent type regardless of allocation strategy) for these functions, I've done that somewhere on the ng or my http server before too, but phobos doesn't do that either. The phobos one also doesn't let you wrap classes which is sometimes useful.
Feb 27 2014
prev sibling parent reply "Szymon Gatner" <noemail gmail.com> writes:
On Thursday, 27 February 2014 at 13:31:45 UTC, Dicebot wrote:
 On Thursday, 27 February 2014 at 13:18:51 UTC, Remo wrote:
 Then the question is why not use structs all the time?
Key class feature is run-time polymorphism (via interfaces/inheritance). I tend to use structs for everything else in my personal code.
That is very similar to my thoughts atm. Explicit call to init() / terminate() are so C :/ It really seems that there is no escape from value semantics and shared_ptr. Worst part is there is no even standard shared/weak pointer provided. I must say I am kindof disappointed by all this. I realize that it is not D's fault but still, it is suppose to be "better C++", and while I do see that wrt to templates / TMP, my favourite feature of C++ are d-tors...
Feb 27 2014
parent "Dicebot" <public dicebot.lv> writes:
On Thursday, 27 February 2014 at 14:29:05 UTC, Szymon Gatner 
wrote:
 Explicit call to init() / terminate() are so C :/
It is much better than C because of `scope(exit) terminate()` though :) Also you can use struct destructors same as in C++
 Worst part is there is no even standard shared/weak pointer 
 provided.
There is http://dlang.org/phobos/std_typecons.html#.RefCounted which helps in some cases.
 I must say I am kindof disappointed by all this. I realize that 
 it is not D's fault but still, it is suppose to be "better 
 C++", and while I do see that wrt to templates / TMP, my 
 favourite feature of C++ are d-tors...
It is not supposed to be "better C++", not anymore at least. Something that dissapoints lot of people and there has been a lot of pushing in this direction lately but historically this domain was under-developed.
Feb 27 2014