October 28, 2013
On Monday, 28 October 2013 at 10:07:15 UTC, Rene Zwanenburg wrote:
> On Sunday, 27 October 2013 at 23:33:55 UTC, Ali Çehreli wrote:
>> That's news to me. I know that objects may never be destroyed but why multiple times? How many lives do they have? ;)
>
> Yeah, I'd like to know this as well. I do remember structs allocated on the heap don't have their destructors called at all due to the GC not being precise, I think.

The fact that structs are movable and there is too few struct runtime reflection makes them noncollectable. However, you can wrap struct inside class, in such case struct dtor will be called.

>
> But one object allowed to be destructed multiple times? That sounds really bad.. If that's true a lot of my code is probably incorrect.

I think one need to be aware of this bug (no dtor), rather than cases when dtor is called multiple times.

import std.stdio;

struct S
{
   int i;
   this(int i)   { writefln("ctor, %X", i); this.i = i; }
   this(this)  { writefln("postblit, %X, %X", &this, i); }
   ~this()     { writefln("dtor, %X, %X", &this, i); }
}

int this_throws() { throw new Exception(""); }

void foo(S s, int i) {}

void main()
{
   try { foo(S(1), this_throws); }
   catch(Exception e) {}
}
October 28, 2013
On 10/28/2013 12:30 PM, Maxim Fomin wrote:

> So do you *know* cases or suspect that they may exists? Or remember some
> bug issue?
>
> Here is my attempt:
>
> import std.stdio;
>
> struct S
> {
>     int i;
>     this(int i)   { writefln("ctor, %X", i); this.i = i; }
>     this(this)  { writefln("postblit, %X, %X", &this, i); }
>     ~this()     { writefln("dtor, %X, %X", &this, i); }
> }
>
> auto foo()
> {
>     S s = S(1);
>     return { s = S(2); } ;
> }
>
> void main()
> {
>     foo()();
> }
>
> ctor, 1
> dtor, 7FFFF7ED8FF8, 1
> ctor, 2
> dtor, 7FFFFFFFDB30, 1
>
> Inside foo() function object 's' is destroyed twice: first time as a
> regular struct at the end of block scope, second time before assigning
> S(2).

Ok, that's too much! :( Inspired by your program, the following delegate completely misses the point:

import std.stdio;

struct S
{
    int i;
    ~this() { i = 666; }
}

auto foo()
{
    S s = S(1);

    // When I see the following delegate, I think "the lifetime of s is
    // extended." I expect my delegate to print 1.
    return { writeln(s); } ;
}

void main()
{
    // Unfortunately, the following prints 666!
    foo()();
}

What is the purpose of writeln in that delegate? Obviously, to print 1. Yet it doesn't happen that way. Is this accepted to be a bug? Should the programmer 'new' the object instead?

Ali

October 29, 2013
On Monday, 28 October 2013 at 19:30:12 UTC, Maxim Fomin wrote:
> Here is my attempt:
>
> import std.stdio;
>
> struct S
> {
>    int i;
>    this(int i)   { writefln("ctor, %X", i); this.i = i; }
>    this(this)  { writefln("postblit, %X, %X", &this, i); }
>    ~this()     { writefln("dtor, %X, %X", &this, i); }
> }
>
> auto foo()
> {
>    S s = S(1);
>    return { s = S(2); } ;
> }
>
> void main()
> {
>    foo()();
> }
>
> ctor, 1
> dtor, 7FFFF7ED8FF8, 1
> ctor, 2
> dtor, 7FFFFFFFDB30, 1
>
> Inside foo() function object 's' is destroyed twice: first time as a regular struct at the end of block scope, second time before assigning S(2).
>
> There are other tools: union bug, control flow tricks, __traits, __dtor but they are move obvious.

That's pretty nasty :). But I suspect this is a bug and not by design. __dtor and __traits are, IMHO, the proverbial escape hatch D should provide, so I think that's OK. I take it that by control flow trick you mean the try/catch example in your other post?

Anyway, thanks for pointing this out. Will probably save me some debugging in the future.
October 29, 2013
On Monday, 28 October 2013 at 19:40:26 UTC, Maxim Fomin wrote:
> The fact that structs are movable and there is too few struct runtime reflection makes them noncollectable. However, you can wrap struct inside class, in such case struct dtor will be called.

Yeah, if wrapping inside a class wouldn't work either we'd be in a whole new world of hurt.

But what do you exactly mean by noncollectable? And what does movability have to do with that? I think the memory will be reclaimed without a problem, so new-ing a struct without destructor would be fine. This doesn't leak:

struct S
{
	int i;
}

void main()
{
	while(true)
	{
		new S;
	}
}
October 29, 2013
On Monday, 28 October 2013 at 20:43:01 UTC, Ali Çehreli wrote:
>
> What is the purpose of writeln in that delegate? Obviously, to print 1. Yet it doesn't happen that way. Is this accepted to be a bug? Should the programmer 'new' the object instead?
>
> Ali

In my opinion it is a corner case, a consequence of two things: 1) need to allocate struct into heap due to lambda 2) need to put dtor invocation in the end as usual.
October 29, 2013
On Tuesday, 29 October 2013 at 11:46:53 UTC, Rene Zwanenburg wrote:
>
> That's pretty nasty :). But I suspect this is a bug and not by design. __dtor and __traits are, IMHO, the proverbial escape hatch D should provide, so I think that's OK. I take it that by control flow trick you mean the try/catch example in your other post?
>

By control flow tricks I mean follows: compiler inserts dtor invocation in the end the function for stack structs and static arrays of struct, so in theory one way to call dtor twice is to jump multiple times just before dtor call, using for example gotos, exceptions or such obscure feature as C setjmp/longjump.

October 29, 2013
On Tuesday, 29 October 2013 at 12:03:09 UTC, Rene Zwanenburg wrote:
> On Monday, 28 October 2013 at 19:40:26 UTC, Maxim Fomin wrote:
>> The fact that structs are movable and there is too few struct runtime reflection makes them noncollectable. However, you can wrap struct inside class, in such case struct dtor will be called.
>
> Yeah, if wrapping inside a class wouldn't work either we'd be in a whole new world of hurt.
>
> But what do you exactly mean by noncollectable? And what does movability have to do with that? I think the memory will be reclaimed without a problem, so new-ing a struct without destructor would be fine. This doesn't leak:
>
> struct S
> {
> 	int i;
> }
>
> void main()
> {
> 	while(true)
> 	{
> 		new S;
> 	}
> }

I would say it leaks because dtor (if defined) is not called, although memory is reclaimed at some point. In my opinion struct movability is a problem for heap struct collection because it is hard to say judging to struct stack/heap pointer whether it should be collected or not. If you look at output from previous example,

ctor, 1
dtor, 7FFFF7ED8FF8, 1
ctor, 2
dtor, 7FFFFFFFDB30, 1

you will see that adressess are different and refer to stack, yet object is in the heap. By the way, there is another issue - if you have delegate inside struct method touching some field, than invoking such delegate after returning from method may break memory, because delegate references 'this' struct pointer, but it may be changed across lifetime. I am not sure whether some algorithm for solving heap struct collectibility can be made, but I don't have any idea right now.
October 29, 2013
On 10/29/2013 08:47 AM, Maxim Fomin wrote:
> On Monday, 28 October 2013 at 20:43:01 UTC, Ali Çehreli wrote:
>>
>> What is the purpose of writeln in that delegate? Obviously, to print
>> 1. Yet it doesn't happen that way. Is this accepted to be a bug?
>> Should the programmer 'new' the object instead?
>>
>> Ali
>
> In my opinion it is a corner case, a consequence of two things: 1) need
> to allocate struct into heap due to lambda 2) need to put dtor
> invocation in the end as usual.

As a continuation of this sub thread, I've opened the following thread in the D newsgroup:

  http://forum.dlang.org/post/l4osr0$2f3q$1@digitalmars.com

Ali

October 29, 2013
On Tuesday, 29 October 2013 at 17:57:01 UTC, Ali Çehreli wrote:
> On 10/29/2013 08:47 AM, Maxim Fomin wrote:
>> On Monday, 28 October 2013 at 20:43:01 UTC, Ali Çehreli wrote:
>>>
>>> What is the purpose of writeln in that delegate? Obviously, to print
>>> 1. Yet it doesn't happen that way. Is this accepted to be a bug?
>>> Should the programmer 'new' the object instead?
>>>
>>> Ali
>>
>> In my opinion it is a corner case, a consequence of two things: 1) need
>> to allocate struct into heap due to lambda 2) need to put dtor
>> invocation in the end as usual.
>
> As a continuation of this sub thread, I've opened the following thread in the D newsgroup:
>
>   http://forum.dlang.org/post/l4osr0$2f3q$1@digitalmars.com
>
> Ali

I did this in 2 January (http://forum.dlang.org/thread/lpljpfjxwobniglwnqvl@forum.dlang.org) and received exactly zero responces.
October 29, 2013
On 10/29/2013 11:11 AM, Maxim Fomin wrote:

> On Tuesday, 29 October 2013 at 17:57:01 UTC, Ali Çehreli wrote:

>>   http://forum.dlang.org/post/l4osr0$2f3q$1@digitalmars.com

> I did this in 2 January
> (http://forum.dlang.org/thread/lpljpfjxwobniglwnqvl@forum.dlang.org) and
> received exactly zero responces.

I will respond to yours after my redundant one settles. :p

Ali