Thread overview
Alternative destructors, do/should we have them?
Jul 05, 2018
Dukc
Jul 05, 2018
Andrea Fontana
Jul 05, 2018
Dukc
Jul 05, 2018
Atila Neves
Jul 05, 2018
Dukc
July 05, 2018
D does not have default constructors for structs, but I have thought that this might get around the problem:

struct MallocedPtr()
{   void* location;
    ~this()
    {   import core.stdc.stdlib;
        assert(location != null);
        free(location.ptr);
    }
}

Unlike a destructor which has a runtime check whether it's initialized, this has no performance cost over a C++-style default-initialized struct. I think "hand grenade RAII" is a perfect name for this idiom, because like a hand grenade, this struct asserts it is set somewhere else after initialization before it's destructor runs.

But there is a problem. If you use std.algorithm.move to give a hand grenade to a function, it initializes another hand grenade for the calling function. I didn't come up with any way to defuse the initialized grenade without runtime cost.

Granted, a runtime check at destructor is unlikely to be a major performance hit for any normal application, but D is a systems language, right? Do you have any ideas to get around this? If not, should we in your opinion have an ability to define an alternative destructor which runs only when explicitly requested?
July 05, 2018
On Thursday, 5 July 2018 at 10:57:51 UTC, Dukc wrote:
> If not, should we in your opinion have an ability to define an alternative destructor which runs only when explicitly requested?

What does "when explicity requested" mean?
July 05, 2018
On Thursday, 5 July 2018 at 10:57:51 UTC, Dukc wrote:
> D does not have default constructors for structs, but I have thought that this might get around the problem:
>
> [...]

You already have that capability:

struct HandGrenade {
    void* ptr;
    void destroy() {
        import core.stdc.stdlib: free;
        free(ptr);
    }
}


This isn't a great example since it's perfectly fine to pass null to core.stdc.stdlib.free.

Atila
July 05, 2018
On Thursday, 5 July 2018 at 15:58:14 UTC, Andrea Fontana wrote:
> On Thursday, 5 July 2018 at 10:57:51 UTC, Dukc wrote:
>> If not, should we in your opinion have an ability to define an alternative destructor which runs only when explicitly requested?
>
> What does "when explicity requested" mean?

That the alternative destructor runs only when you ask it to. There would be some way to say before an end of a block, return statement, break statement ect that you want the alternative destructor to be applied to the struct.

The normal destructor would not run when an alternative one is used, but would run otherwise.

In fact, in this case it would be enough to elide the destructor somehow.
July 05, 2018
On Thursday, 5 July 2018 at 16:12:08 UTC, Atila Neves wrote:
> On Thursday, 5 July 2018 at 10:57:51 UTC, Dukc wrote:
>> D does not have default constructors for structs, but I have thought that this might get around the problem:
>>
>> [...]
>
> You already have that capability:
>
> struct HandGrenade {
>     void* ptr;
>     void destroy() {
>         import core.stdc.stdlib: free;
>         free(ptr);
>     }
> }
>
>
> This isn't a great example since it's perfectly fine to pass null to core.stdc.stdlib.free.
>
> Atila

On Thursday, 5 July 2018 at 16:12:08 UTC, Atila Neves wrote:
> This isn't a great example since it's perfectly fine to pass null to core.stdc.stdlib.free.
>
> Atila

You're right. Well, It could be some custom allocation table that does not check for such things:

struct HandGrenade
{    void* ptr;
     ~this()
     {   foreach
        (   ref _byte;
            cast(ubyte[]) ptr[0 .. memoryTable.assumeSorted.upperBound(ptr).front - ptr]
        ) _byte = 0;
     }
}