Thread overview
is struct delete deterministic? (cf used in Unique)
Mar 07, 2015
Timothee Cour
Mar 08, 2015
weaselcat
Mar 08, 2015
Timothee Cour
Mar 08, 2015
weaselcat
Mar 08, 2015
Jonathan M Davis
Mar 08, 2015
Jonathan M Davis
Mar 08, 2015
Timothee Cour
Mar 09, 2015
Jonathan M Davis
March 07, 2015
I'm a little confused about the following:
clear,delete,destroy.
My understanding is that clear is deprecated and delete is planned to be
deprecated, so we should only ever use destroy (which deterministic calls
the destructor but doesn't release memory).

Unique uses delete however in the destructor. Is that still guaranteeing deterministic destruction when the uniqued element is either a class or struct? (ie if the destructor has a file handle resource, will it be deterministically freed?)


March 08, 2015
On Saturday, 7 March 2015 at 23:48:39 UTC, Timothee Cour wrote:
> I'm a little confused about the following:
> clear,delete,destroy.
> My understanding is that clear is deprecated and delete is planned to be
> deprecated, so we should only ever use destroy (which deterministic calls
> the destructor but doesn't release memory).
>
> Unique uses delete however in the destructor. Is that still guaranteeing
> deterministic destruction when the uniqued element is either a class or
> struct? (ie if the destructor has a file handle resource, will it be
> deterministically freed?)

structs are allocated on the stack(unless instantiated with new), and call their destructor when you leave their scope. Unique still guarantees deterministic destruction because it's wrapped around a struct, it's a fairly common 'D idiom' I'd say(i.e, look at how File is implemented - D's runtime and standard library are surprisingly well documented and easy to read.)

I'm not sure why Unique uses delete, might just be bitrot.
March 08, 2015
To clarify, I'm only asking about a struct allocated via new.
Unique!T is wrapped around a struct, but it allocates a struct T via 'new',
so my question still holds: does 'delete t' (where t is a struct allocated
via new) guarantee deterministic destruction?

I'm guessing yes, otherwise Unique would be broken, but where is that
specified in the docs?
And if delete is to be deprecated (according to the docs), what is the
correct way to do that (despite fact that Unique relies on delete).


On Sat, Mar 7, 2015 at 4:02 PM, weaselcat via Digitalmars-d-learn < digitalmars-d-learn@puremagic.com> wrote:

> On Saturday, 7 March 2015 at 23:48:39 UTC, Timothee Cour wrote:
>
>> I'm a little confused about the following:
>> clear,delete,destroy.
>> My understanding is that clear is deprecated and delete is planned to be
>> deprecated, so we should only ever use destroy (which deterministic calls
>> the destructor but doesn't release memory).
>>
>> Unique uses delete however in the destructor. Is that still guaranteeing deterministic destruction when the uniqued element is either a class or struct? (ie if the destructor has a file handle resource, will it be deterministically freed?)
>>
>
> structs are allocated on the stack(unless instantiated with new), and call their destructor when you leave their scope. Unique still guarantees deterministic destruction because it's wrapped around a struct, it's a fairly common 'D idiom' I'd say(i.e, look at how File is implemented - D's runtime and standard library are surprisingly well documented and easy to read.)
>
> I'm not sure why Unique uses delete, might just be bitrot.
>


March 08, 2015
On Sunday, 8 March 2015 at 01:20:57 UTC, Timothee Cour wrote:
> To clarify, I'm only asking about a struct allocated via new.
> Unique!T is wrapped around a struct, but it allocates a struct T via 'new',
> so my question still holds: does 'delete t' (where t is a struct allocated
> via new) guarantee deterministic destruction?
>
> I'm guessing yes, otherwise Unique would be broken, but where is that
> specified in the docs?
> And if delete is to be deprecated (according to the docs), what is the
> correct way to do that (despite fact that Unique relies on delete).
>
>
> On Sat, Mar 7, 2015 at 4:02 PM, weaselcat via Digitalmars-d-learn <
> digitalmars-d-learn@puremagic.com> wrote:
>
>> On Saturday, 7 March 2015 at 23:48:39 UTC, Timothee Cour wrote:
>>
>>> I'm a little confused about the following:
>>> clear,delete,destroy.
>>> My understanding is that clear is deprecated and delete is planned to be
>>> deprecated, so we should only ever use destroy (which deterministic calls
>>> the destructor but doesn't release memory).
>>>
>>> Unique uses delete however in the destructor. Is that still guaranteeing
>>> deterministic destruction when the uniqued element is either a class or
>>> struct? (ie if the destructor has a file handle resource, will it be
>>> deterministically freed?)
>>>
>>
>> structs are allocated on the stack(unless instantiated with new), and call
>> their destructor when you leave their scope. Unique still guarantees
>> deterministic destruction because it's wrapped around a struct, it's a
>> fairly common 'D idiom' I'd say(i.e, look at how File is implemented - D's
>> runtime and standard library are surprisingly well documented and easy to
>> read.)
>>
>> I'm not sure why Unique uses delete, might just be bitrot.

Unique!T allocates via new, but itself is meant to be allocated on the stack. When it leaves the scope it calls delete on its contents(if they're still valid - i.e, haven't been moved to a different Unique!T)

delete guarantees deterministic destruction because structs guarantee deterministic destruction, and Unique!T itself is a struct.

http://dlang.org/cpptod.html#raii

To answer your questions,
1. Yes, Unique!T guarantees deterministic destruction of T(unless there are bugs I'm unaware of.)
2. It's on the deprecated page. http://dlang.org/deprecate.html#delete
March 08, 2015
On Saturday, March 07, 2015 17:20:49 Timothee Cour via Digitalmars-d-learn wrote:
> To clarify, I'm only asking about a struct allocated via new.
> Unique!T is wrapped around a struct, but it allocates a struct T via 'new',
> so my question still holds: does 'delete t' (where t is a struct allocated
> via new) guarantee deterministic destruction?
>
> I'm guessing yes, otherwise Unique would be broken, but where is that
> specified in the docs?
> And if delete is to be deprecated (according to the docs), what is the
> correct way to do that (despite fact that Unique relies on delete).

Yes, delete is deterministic. It's basically the same as what you get in C++ except that it's using the GC heap and therefore is not safe. delete is supposed to have been deprecated but has not been yet (mostly because no one has gotten around to doing it).

If you're using the GC heap and want to destroy an object, that's what destroy is for - but it doesn't free the memory, because that's not safe. You can free the memory with core.memory.GC.free, but you have to have destroyed the object first, since free just frees memory. But that's just duplicating what delete does, so it's still unsafe.

What's generally considered the correct way to deal with manual memory management involves allocating using C's malloc, constructing via emplace, and then using destroy and C's free to destroy the object and free its memory when you're done. But that's way more of a pain then using new and then delete, which is probably part of why some folks still use delete (in the case of Unique though, I expect that it's just because it's been around a while). Hopefully, the standard allocator stuff will make it as simple as using new and delete though - e.g. something like

auto ptr = alloc.make!Myobj(arg1, arg2);
alloc.free(ptr);

but the standard allocator stuff isn't currently far enough along yet for us to be at that point unfortunately.

- Jonathan M Davis

March 08, 2015
On Sunday, March 08, 2015 04:13:28 Jonathan M Davis via Digitalmars-d-learn wrote:
> On Saturday, March 07, 2015 17:20:49 Timothee Cour via Digitalmars-d-learn wrote:
> > To clarify, I'm only asking about a struct allocated via new.
> > Unique!T is wrapped around a struct, but it allocates a struct T via 'new',
> > so my question still holds: does 'delete t' (where t is a struct allocated
> > via new) guarantee deterministic destruction?
> >
> > I'm guessing yes, otherwise Unique would be broken, but where is that
> > specified in the docs?
> > And if delete is to be deprecated (according to the docs), what is the
> > correct way to do that (despite fact that Unique relies on delete).
>
> Yes, delete is deterministic. It's basically the same as what you get in C++ except that it's using the GC heap and therefore is not safe. delete is supposed to have been deprecated but has not been yet (mostly because no one has gotten around to doing it).
>
> If you're using the GC heap and want to destroy an object, that's what destroy is for - but it doesn't free the memory, because that's not safe. You can free the memory with core.memory.GC.free, but you have to have destroyed the object first, since free just frees memory. But that's just duplicating what delete does, so it's still unsafe.
>
> What's generally considered the correct way to deal with manual memory management involves allocating using C's malloc, constructing via emplace, and then using destroy and C's free to destroy the object and free its memory when you're done. But that's way more of a pain then using new and then delete, which is probably part of why some folks still use delete (in the case of Unique though, I expect that it's just because it's been around a while). Hopefully, the standard allocator stuff will make it as simple as using new and delete though - e.g. something like
>
> auto ptr = alloc.make!Myobj(arg1, arg2);
> alloc.free(ptr);
>
> but the standard allocator stuff isn't currently far enough along yet for us to be at that point unfortunately.

I would point out though that until recently, the GC never ran the destructors for structs on the heap, because it didn't have the type information to do it. So, if you did

auto s = new MyStruct;

its destructor never ran, even if the GC collected it (which it's not guaranteed to do with any memory). But I don't know if the destructor was run if you expliictly called delete on the pointer to the struct.

However, there has recently been work done to make it so that struct destructors on the heap _are_ run when a struct is collected by the GC, so the situation there is improving, and if delete didn't call the destructor before, it probably will with the next release.

- Jonathan M Davis

March 08, 2015
On Sun, Mar 8, 2015 at 4:36 AM, Jonathan M Davis via Digitalmars-d-learn < digitalmars-d-learn@puremagic.com> wrote:

> On Sunday, March 08, 2015 04:13:28 Jonathan M Davis via Digitalmars-d-learn wrote:
> > On Saturday, March 07, 2015 17:20:49 Timothee Cour via
> Digitalmars-d-learn wrote:
> > > To clarify, I'm only asking about a struct allocated via new. Unique!T is wrapped around a struct, but it allocates a struct T via
> 'new',
> > > so my question still holds: does 'delete t' (where t is a struct
> allocated
> > > via new) guarantee deterministic destruction?
> > >
> > > I'm guessing yes, otherwise Unique would be broken, but where is that
> > > specified in the docs?
> > > And if delete is to be deprecated (according to the docs), what is the
> > > correct way to do that (despite fact that Unique relies on delete).
> >
> > Yes, delete is deterministic. It's basically the same as what you get in
> C++
> > except that it's using the GC heap and therefore is not safe. delete is supposed to have been deprecated but has not been yet (mostly because no
> one
> > has gotten around to doing it).
> >
> > If you're using the GC heap and want to destroy an object, that's what destroy is for - but it doesn't free the memory, because that's not safe. You can free the memory with core.memory.GC.free, but you have to have destroyed the object first, since free just frees memory. But that's just duplicating what delete does, so it's still unsafe.
> >
> > What's generally considered the correct way to deal with manual memory management involves allocating using C's malloc, constructing via
> emplace,
> > and then using destroy and C's free to destroy the object and free its memory when you're done. But that's way more of a pain then using new and then delete, which is probably part of why some folks still use delete
> (in
> > the case of Unique though, I expect that it's just because it's been
> around
> > a while). Hopefully, the standard allocator stuff will make it as simple
> as
> > using new and delete though - e.g. something like
> >
> > auto ptr = alloc.make!Myobj(arg1, arg2);
> > alloc.free(ptr);
> >
> > but the standard allocator stuff isn't currently far enough along yet
> for us
> > to be at that point unfortunately.
>
> I would point out though that until recently, the GC never ran the destructors for structs on the heap, because it didn't have the type information to do it. So, if you did
>
> auto s = new MyStruct;
>
> its destructor never ran, even if the GC collected it (which it's not guaranteed to do with any memory). But I don't know if the destructor was run if you expliictly called delete on the pointer to the struct.
>

Thanks for you answers, however this last sentence worries me. According to it there's no guarantee then?


>
> However, there has recently been work done to make it so that struct destructors on the heap _are_ run when a struct is collected by the GC, so the situation there is improving, and if delete didn't call the destructor before, it probably will with the next release.
>
> - Jonathan M Davis
>
>


March 09, 2015
On Sunday, March 08, 2015 14:04:52 Timothee Cour via Digitalmars-d-learn wrote:
> On Sun, Mar 8, 2015 at 4:36 AM, Jonathan M Davis via Digitalmars-d-learn <
> > I would point out though that until recently, the GC never ran the destructors for structs on the heap, because it didn't have the type information to do it. So, if you did
> >
> > auto s = new MyStruct;
> >
> > its destructor never ran, even if the GC collected it (which it's not guaranteed to do with any memory). But I don't know if the destructor was run if you expliictly called delete on the pointer to the struct.
> >
>
> Thanks for you answers, however this last sentence worries me. According to it there's no guarantee then?

Previously, struct destructors were _never_ run by the GC, because it didn't have the required type information. What I don't know is whether delete called a struct's destructor or not. But if it didn't, then it never did. There was no maybe about it. Either it always did, or it never did. I just don't know which it is, because I haven't really used delete, and I don't recall anyone discussing whether delete had the same problem that the GC does when it runs (I'd guess not, but I'd have to test it).

With the upcoming release, however, it's been changed so that struct destructors _do_ get called by the GC, which would presumably make it so that delete calls the struct's destructor if it didn't before.

I guess that I can just revert my dmd to an older release and see what happens there (I'm normally sitting on master)... Yeah. delete calls the struct's destructor even though the GC doesn't. And there's nothing non-deterministic about it. The GC isn't guaranteed to collect something (so even with the recent changes with regards to structs, there's still no guarantee that their destructors will be run), but delete is, since you're explicitly telling it to. It was just a question of whether delete had the same problem that the GC did and couldn't run the struct's destructor. But fortunately, that doesn't seem to be the case.

- Jonathan M Davis