Re: class destruction

2015-09-09 Thread ponce via Digitalmars-d-learn

On Wednesday, 9 September 2015 at 07:19:58 UTC, Q wrote:
Hi. I'm playing around with D for a while and I would like to 
switch. But here is one thing, I need an answer for. In the 
Docs is mentioned that it is not sure that the DTor of a class 
is called. But what if I have struct, which holds a C Handle 
which is destroyed as soon as the struct gets destroyed (more 
or less like a unique pointer) and I stick this struct into a 
class (because I strongly need polymorphism)?


Then you have to make sure the class destruction happens and not 
rely on the GC.



Can I be sure that the Handle is destroyed as soon as the class 
is destroyed?


I think that yes, struct members are destroyed. But you need to 
make sure the class is destroyed.






If so there are only two ways that come to mind:
1.  the class holds only a pointer to the struct, which is 
unsafe since I must guarantee that the struct lives as long as 
the class
2. the class gets a close/finalize/destroy method (or is called 
with the built in destroy method), which is a absolute nogo, 
because it is absolutly sure that this can be forgotten. 
Besides, we live in 2015 and that is not C where I have to 
clean my code manually, so this option would be ridiculous :D


I'm gratefull for any answers and ideas.


I'm using the manual method after much hair-pulling: 
http://p0nce.github.io/d-idioms/#GC-proof-resource-class


It absolutely is worse than the C++ situation, however with the 
above pattern leaks will be reported by the GC, which is a nice 
consolation prize.



Alternatively, stick your class in Unique! / Refcounted! / scoped!






Re: class destruction

2015-09-09 Thread Kagamin via Digitalmars-d-learn

On Wednesday, 9 September 2015 at 07:19:58 UTC, Q wrote:
Besides, we live in 2015 and that is not C where I have to 
clean my code manually, so this option would be ridiculous :D


The difference is that in C you need to manage POD memory too. 
Manual management of non-POD resources is a problem of a smaller 
size, and you can use RAII too.


Re: class destruction

2015-09-09 Thread Q via Digitalmars-d-learn
But if others use my code they must think about finalizing the 
classes? That is very awkward.
I'll take a look at Rust and otherwise I will stick with C++. 
Thanks for you answer. :)


Re: class destruction

2015-09-09 Thread ponce via Digitalmars-d-learn

On Wednesday, 9 September 2015 at 14:36:24 UTC, Q wrote:
But if others use my code they must think about finalizing the 
classes? That is very awkward.


classes, yes but structs, no.

I'll take a look at Rust and otherwise I will stick with C++. 
Thanks for you answer. :)


Well, resource management is only part of the story.


Re: class destruction

2015-09-09 Thread Q via Digitalmars-d-learn
On Wednesday, 9 September 2015 at 15:32:58 UTC, Adam D. Ruppe 
wrote:

On Wednesday, 9 September 2015 at 15:24:57 UTC, Q wrote:

I thought that is not guaranteed, according to the docs?


It is possible that the GC will never actually run, but you can 
force it to if you need it to by calling GC.collect at any time.


Yes, but according to the specs it is not guaranteed that the GC 
calls the DTor if the Object is collected.


Re: class destruction

2015-09-09 Thread Q via Digitalmars-d-learn
On Wednesday, 9 September 2015 at 14:57:26 UTC, Adam D. Ruppe 
wrote:

On Wednesday, 9 September 2015 at 07:19:58 UTC, Q wrote:
Can I be sure that the Handle is destroyed as soon as the 
class is destroyed?


It will do that automatically.

Like the others said, you won't be sure when the class is 
destroyed unless you have the user code take ownership of it. 
(This btw is the same as C++, just in C++ the ownership syntax 
is a wee bit shorter.)


C++:

class Foo {
  public:
   Foo() { /* acquire */ }
   ~Foo() { /* destroy */ }
};

void useFoo(Foo* foo) { }

// pretend I did the header separation here

int main() {
   Foo foo;
   useFoo();
   return 0;
}


D:

--
module foo;

class Foo {
   private this() { /* acquire */ }
   ~this() { /* destroy */ }
}

struct OwnedFoo(F) {
F foo;
alias foo this;
~this() {
.destroy(foo);
}

@disable this(this) {}
}

auto create(F, T...)(T t) if(is(F : Foo)) {
return OwnedFoo!F(new F(t));
}
--

--
module main;
import foo;

void useFoo(Foo foo) {}

void main() {
   auto foo = create!Foo();
}
---


The code is a bit longer since the owned pointer in the 
standard library isn't exactly what I wanted, but you could use 
std.typecons.Unique too. (Actually, it does offer a bit more 
safety in reference escaping than mine. But mine is the closest 
to C++ default).



The private constructor means it won't let you bypass the owned 
factory when creating it. A bit extra code in foo means all 
uses of it will be simple like in main.


Just don't store the reference after it is destroyed, just like 
you would need to be careful with in C++. Using the library 
Unique will help you get this right too if you want to learn 
that.


But in C++, classes and structs are value types _and_ 
extendable.There is no pressure to heap allocate a class. Of 
course, if I do that, I use a unique_ptr (shared_ptr is almost 
everytime misplaced).
But since D has a GC and (per default) force to heap allocate a 
class. So IMO the GC should also destroy it, everything else is 
just awkward. I don't want to hack around in a new language. I 
think Rust offers my all I want. But thanks for the explanation.




Re: class destruction

2015-09-09 Thread Q via Digitalmars-d-learn
And sorry if that sounds rude, I'm just in a hurry. I just think 
D is not mature enough for serious stuff. :) That is of course 
only my personal opinion.


Re: class destruction

2015-09-09 Thread Adam D. Ruppe via Digitalmars-d-learn

On Wednesday, 9 September 2015 at 15:24:57 UTC, Q wrote:

I thought that is not guaranteed, according to the docs?


It is possible that the GC will never actually run, but you can 
force it to if you need it to by calling GC.collect at any time.


Re: class destruction

2015-09-09 Thread Adam D. Ruppe via Digitalmars-d-learn

On Wednesday, 9 September 2015 at 15:37:50 UTC, Q wrote:
Yes, but according to the specs it is not guaranteed that the 
GC calls the DTor if the Object is collected.


Where? This page says pretty plainly:

http://dlang.org/class.html#destructors

"The garbage collector calls the destructor function when the 
object is deleted."


(this is arguably a mistake, dtor and finalizer being the same 
thing have been a problem before, but it does say that)


This sentence: "The garbage collector is not guaranteed to run 
the destructor for all unreferenced objects. " is because the GC 
is conservative and has a few exceptions in what it covers. But 
if you aren't one of those exceptions (data segment, or pinned by 
a false pointer (very rare in 64 bit btw), it will be collected 
and if it is collected, the dtor is run.


Re: class destruction

2015-09-09 Thread Meta via Digitalmars-d-learn

On Wednesday, 9 September 2015 at 15:37:50 UTC, Q wrote:
Yes, but according to the specs it is not guaranteed that the 
GC calls the DTor if the Object is collected.


Note that I believe this is the same as in Java (though not C#, 
interestingly enough). In Java an object's destructor is not 
guaranteed to run.


Re: class destruction

2015-09-09 Thread Adam D. Ruppe via Digitalmars-d-learn

On Wednesday, 9 September 2015 at 07:19:58 UTC, Q wrote:
Can I be sure that the Handle is destroyed as soon as the class 
is destroyed?


It will do that automatically.

Like the others said, you won't be sure when the class is 
destroyed unless you have the user code take ownership of it. 
(This btw is the same as C++, just in C++ the ownership syntax is 
a wee bit shorter.)


C++:

class Foo {
  public:
   Foo() { /* acquire */ }
   ~Foo() { /* destroy */ }
};

void useFoo(Foo* foo) { }

// pretend I did the header separation here

int main() {
   Foo foo;
   useFoo();
   return 0;
}


D:

--
module foo;

class Foo {
   private this() { /* acquire */ }
   ~this() { /* destroy */ }
}

struct OwnedFoo(F) {
F foo;
alias foo this;
~this() {
.destroy(foo);
}

@disable this(this) {}
}

auto create(F, T...)(T t) if(is(F : Foo)) {
return OwnedFoo!F(new F(t));
}
--

--
module main;
import foo;

void useFoo(Foo foo) {}

void main() {
   auto foo = create!Foo();
}
---


The code is a bit longer since the owned pointer in the standard 
library isn't exactly what I wanted, but you could use 
std.typecons.Unique too. (Actually, it does offer a bit more 
safety in reference escaping than mine. But mine is the closest 
to C++ default).



The private constructor means it won't let you bypass the owned 
factory when creating it. A bit extra code in foo means all uses 
of it will be simple like in main.


Just don't store the reference after it is destroyed, just like 
you would need to be careful with in C++. Using the library 
Unique will help you get this right too if you want to learn that.


Re: class destruction

2015-09-09 Thread Adam D. Ruppe via Digitalmars-d-learn

On Wednesday, 9 September 2015 at 15:10:33 UTC, Q wrote:
But since D has a GC and (per default) force to heap allocate a 
class. So IMO the GC should also destroy it, everything else is 
just awkward.


Well, it *does* by default. If that's what you want, just do it 
the plain way with simple `new`. It will be destroyed (and any 
structs inside also destroyed) when the GC gets it.




Re: class destruction

2015-09-09 Thread Q via Digitalmars-d-learn
On Wednesday, 9 September 2015 at 15:19:04 UTC, Adam D. Ruppe 
wrote:

On Wednesday, 9 September 2015 at 15:10:33 UTC, Q wrote:
But since D has a GC and (per default) force to heap allocate 
a class. So IMO the GC should also destroy it, everything else 
is just awkward.


Well, it *does* by default. If that's what you want, just do it 
the plain way with simple `new`. It will be destroyed (and any 
structs inside also destroyed) when the GC gets it.


I thought that is not guaranteed, according to the docs?