Re: Destructor call

2018-04-10 Thread Steven Schveighoffer via Digitalmars-d-learn

On 4/10/18 3:24 PM, Jonathan M Davis wrote:

On Tuesday, April 10, 2018 18:52:19 kinke via Digitalmars-d-learn wrote:

On Tuesday, 10 April 2018 at 18:34:54 UTC, n0fun wrote:

Why the destructor is called in the second case and why not in
the first?


The first case is RAII, where destruction isn't done for not
fully constructed instances.


Yeah, which is arguably a bug:

https://issues.dlang.org/show_bug.cgi?id=14246


The second case is GC finalization at program shutdown and looks
like a bug, as the GC should probably immediately reclaim the
allocated heap memory if construction wasn't successful.


Maybe it should reclaim the memory immediately, but I don't see how it could
be argued to be a bug. When memory is freed by the GC is an implementation
detail, and it's never guaranteed that a finalizer will actually ever run.


Actually, it is a bug, because the destructor is going to run the 
finalizer on a collection cycle, and the object may be partially created.


This is due to the way it's created using new:

1. a memory block is allocated
2. The typeinfo is stored in the block
3. The runtime returns the pointer to the block.
4. the compiler calls the constructor on the block.

Because the typeinfo is unconditionally stored, the finalizer will run, 
even if it shouldn't.


The issue is that the compiler is much better at calling the constructor 
of the struct. This means we need 2 hooks for the construction -- 1. the 
memory allocation, and 2. a "post construction" call. I'd hate to pass 
the constructor parameters to a template function rather than the 
compiler handle all of these messy details.


-Steve


Re: Destructor call

2018-04-10 Thread Jonathan M Davis via Digitalmars-d-learn
On Tuesday, April 10, 2018 18:52:19 kinke via Digitalmars-d-learn wrote:
> On Tuesday, 10 April 2018 at 18:34:54 UTC, n0fun wrote:
> > Why the destructor is called in the second case and why not in
> > the first?
>
> The first case is RAII, where destruction isn't done for not
> fully constructed instances.

Yeah, which is arguably a bug:

https://issues.dlang.org/show_bug.cgi?id=14246

> The second case is GC finalization at program shutdown and looks
> like a bug, as the GC should probably immediately reclaim the
> allocated heap memory if construction wasn't successful.

Maybe it should reclaim the memory immediately, but I don't see how it could
be argued to be a bug. When memory is freed by the GC is an implementation
detail, and it's never guaranteed that a finalizer will actually ever run.

- Jonathan M Davis



Re: Destructor call

2018-04-10 Thread kinke via Digitalmars-d-learn

On Tuesday, 10 April 2018 at 18:34:54 UTC, n0fun wrote:
Why the destructor is called in the second case and why not in 
the first?


The first case is RAII, where destruction isn't done for not 
fully constructed instances.
The second case is GC finalization at program shutdown and looks 
like a bug, as the GC should probably immediately reclaim the 
allocated heap memory if construction wasn't successful.


Destructor call

2018-04-10 Thread n0fun via Digitalmars-d-learn

import std.stdio;

struct S(alias n) {
this(int) {
throw new Exception("Exception");
}
~this() {
writeln("destructor " ~ n);
}
}

void main() {
writeln("--- 1 ---");
try {
auto s = S!"1"(0);
} catch (Exception) {}
writeln("--- 2 ---");
try {
auto s = new S!"2"(0);
} catch (Exception) {}
}

Output:
--- 1 ---
--- 2 ---
destructor 2

Why the destructor is called in the second case and why not in 
the first?

How to design structs with such different behavior?



Re: Missing destructor call using clear and base interface ref.

2012-08-09 Thread Roberto Delfiore

Thank you for your analysis, it's a very strange behavior. I
still can not figure out if there is something I don't know or if
it's is simply a bug.

Good answer: Shouldn't destroy() work on an interface?

On Monday, 6 August 2012 at 20:46:45 UTC, Ali Çehreli wrote:

On 08/06/2012 06:59 AM, Roberto Delfiore wrote:
 See the following code:

 interface A{
 }

 class B : A{
 this(string name){this.name = name;}
 ~this(){
 writefln(Destructor %s, name);
 }
 string name;
 }

 void main(){
 B b0 = new B(b0);
 B b1 = new B(b1);

 A a = b0;
 clear(a);

 clear(b1);
 }

 Output:
 Destructor b1

 dmd 2.059

 Why is the B destructor not invoked in the first clear?

 Expected output:
 Destructor b0
 Destructor b1


Interesting.

I've tested the code with 2.060 after replacing 'clear' with 
'destroy' (not required here, but because clear will be 
deprecated):


import std.stdio;

interface A{
}

class B : A{
this(string name){this.name = name;}
~this(){
writefln(Destructor %s, name);
}
string name;
}

void main(){
B b0 = new B(b0);
B b1 = new B(b1);

A a = b0;
writeln(Before clear(a));
destroy(a);

writeln(Before clear(b1));
destroy(b1);

writeln(Leaving main);
}

I see both of the destructor calls but the first one is 
executed out of order:


Before clear(a)
Before clear(b1)
Destructor b1
Leaving main
Destructor b0-- Here

Making 'a' a B produces the expected output:

B a = b0;

Before clear(a)
Destructor b0-- Now at expected time
Before clear(b1)
Destructor b1
Leaving main

I guess destroy() is a no-op on an interface because your not 
seeing the destructor's effect and my seeing it can be 
explained by the non-deterministic behavior of the GC regarding 
destructor calls: If it is up to the GC, the destructor calls 
are not guaranteed.


Do others know? Shouldn't destroy() work on an interface?

Ali


Re: Missing destructor call using clear and base interface ref.

2012-08-09 Thread Denis Shelomovskij

09.08.2012 12:36, Roberto Delfiore пишет:

Thank you for your analysis, it's a very strange behavior. I
still can not figure out if there is something I don't know or if
it's is simply a bug.

Good answer: Shouldn't destroy() work on an interface?



Filled an issue:
http://d.puremagic.com/issues/show_bug.cgi?id=8527

--
Денис В. Шеломовский
Denis V. Shelomovskij


Missing destructor call using clear and base interface ref.

2012-08-06 Thread Roberto Delfiore

See the following code:

interface A{
}

class B : A{
this(string name){this.name = name;}
~this(){
writefln(Destructor %s, name);
}
string name;
}

void main(){
B b0 = new B(b0);
B b1 = new B(b1);

A a = b0;
clear(a);

clear(b1);
}

Output:
Destructor b1

dmd 2.059

Why is the B destructor not invoked in the first clear?

Expected output:
Destructor b0
Destructor b1



Re: Missing destructor call using clear and base interface ref.

2012-08-06 Thread Ali Çehreli

On 08/06/2012 06:59 AM, Roberto Delfiore wrote:
 See the following code:

 interface A{
 }

 class B : A{
 this(string name){this.name = name;}
 ~this(){
 writefln(Destructor %s, name);
 }
 string name;
 }

 void main(){
 B b0 = new B(b0);
 B b1 = new B(b1);

 A a = b0;
 clear(a);

 clear(b1);
 }

 Output:
 Destructor b1

 dmd 2.059

 Why is the B destructor not invoked in the first clear?

 Expected output:
 Destructor b0
 Destructor b1


Interesting.

I've tested the code with 2.060 after replacing 'clear' with 'destroy' 
(not required here, but because clear will be deprecated):


import std.stdio;

interface A{
}

class B : A{
this(string name){this.name = name;}
~this(){
writefln(Destructor %s, name);
}
string name;
}

void main(){
B b0 = new B(b0);
B b1 = new B(b1);

A a = b0;
writeln(Before clear(a));
destroy(a);

writeln(Before clear(b1));
destroy(b1);

writeln(Leaving main);
}

I see both of the destructor calls but the first one is executed out of 
order:


Before clear(a)
Before clear(b1)
Destructor b1
Leaving main
Destructor b0-- Here

Making 'a' a B produces the expected output:

B a = b0;

Before clear(a)
Destructor b0-- Now at expected time
Before clear(b1)
Destructor b1
Leaving main

I guess destroy() is a no-op on an interface because your not seeing the 
destructor's effect and my seeing it can be explained by the 
non-deterministic behavior of the GC regarding destructor calls: If it 
is up to the GC, the destructor calls are not guaranteed.


Do others know? Shouldn't destroy() work on an interface?

Ali