On Tuesday, 25 August 2015 at 22:35:57 UTC, Jim Hewes wrote:
Although C++ can be ugly, one reason I keep going back to it
rather then commit more time to reference-based languages like
C# is because I like deterministic destruction so much. My
question is whether D can REALLY handle this or not. I've not
been sure about this for some time so now I'm just going to
come out and finally ask.
I know about this RAII section in the documentation:
http://dlang.org/cpptod.html#raii
But I don't believe that handles all cases, such as having
classes as member variables of other classes. (Do the members
get destructors called too?)
Then there is std.typecons.Unique and std.typecons.RefCounted.
With these, can I really get deterministic destruction for all
cases like I would in C++?
If so, it might be a good idea to emphasize this more in the
documentation because I'd think people coming from C++ would be
looking for this.
Jim
Hi Jim. RAII in D is a common issue for people coming from C++. I
don't know everything on the subject and would be glad to be
corrected if I write a mistake but here is my share on the
subject.
There are two very different kind of objects in D and memory
management is different for each: structs and classes. I think
you mostly want to hear about classes, but I think each should be
studied nonetheless.
Structs:
=====
Why would you use structs?
- They are stack-allocated by default (but can be heap-allocated
at will)
- They are destroyed at the end of the scope, hence supporting
RAII properly
- They provide rather nice idioms for RAII [1]
- They support single-inheritance through “alias this”
- They support compile-time polymorphism through templates
- They support complex object composition through template mixins
[2]
Why wouldn't you use structs?
- You want to plug yourself on an already existing class-based
system
- You want to use interfaces
- You need runtime-polymorphism
Classes:
=====
Why would you use classes?
- They are heap-based and managed by the GC: lazy destruction
- They provide full support for inheritance and OOP (including
interfaces)
- They support compile-time polymorphism through templates
- They support complex object composition through template mixins
[2]
Why wouldn't use classes?
- They are heap-based
- They don't allow deterministic implicit destruction
How to solve these problems?
==================
Classes don't have *implicit* deterministic destruction but
nothing prevents you from calling a destructor explicitely (be it
~this or another dedicated function). This can be easily done
using scope(...) statements. If this is cumbersome,
std.typecons.Unique and std.typecons.RefCounted can be used to
provide a comportment analogous to that of modern C++. We said
that structs are scope-based, a solution is to wrap an object
into a struct and set the structs destructor to destroy the
object as well at the end of the scope. std.typecons.scoped
provides a nice wrapper arround this behaviour. The destruction
of an object doesn't mean the destruction of the objects that it
referenced. That can also be done explicitely.
A word on the GC
===========
I see a lot of C++ programmer who come to D with a single thought
in mind: “Avoid the GC at all cost, let me manage my damn
memory”. This is understandable, yet biaised. True, a GC isn't
for all applications, but it has its place. Instead of fearing
it, learning to use it well is important. One often doesn't need
deterministic destruction. Lazy destruction has its benefits. I
strongly advise not to rush trying to avoid the GC, instead
profile profile profile.
Conclusion
=======
Doing RAII is possible for structs and for classes, but it is
*really* easier with structs. D structs are really powerful and
often underestimated by newcommers who rush on the "class"
keyword. D classes aren't C++ classes. My advice would be to use
structs as much as possible, to use classes where needed relying
on the GC, and after profiling to introduce RAII behaviour into
problematic classes.
[1]
https://w0rp.com/blog/post/an-raii-constructor-by-another-name-is-just-as-sweet/
[2]
https://blog.dicebot.lv/posts/2015/08/OOP_composition_with_mixins