Thread overview
Disabling struct destructor illegal?
Jul 19, 2018
RazvanN
Jul 19, 2018
Jim Balter
Jul 19, 2018
RazvanN
Jul 19, 2018
Simen Kjærås
Jul 19, 2018
Jonathan M Davis
Jul 20, 2018
Jim Balter
July 19, 2018
struct A
{
    int a;
    @disable ~this() {}
}

void main()
{
    A a = A(2);
}

Currently, this code yields:

Error: destructor `A.~this` cannot be used because it is annotated with @disable

I was expecting that disabling the destructor would make it as if the struct does not have a destructor, instead it makes the program not compile. I find this behavior odd: why not make it illegal to disable the destructor if disabling it will surely result in errors wherever the struct is used. The only situation where the code will compile is A is never used directly. To make matters even more confusing, this code compiles:

class A
{
    int a;
    @disable ~this() {}
}

void main()
{
    A a = new A();
}


So, is this a bug or am I missing something?

Yoroshiku onegaishimasu,
RazvanN

July 19, 2018
On Thursday, 19 July 2018 at 08:50:15 UTC, RazvanN wrote:
> struct A
> {
>     int a;
>     @disable ~this() {}
> }
>
> void main()
> {
>     A a = A(2);
> }
>
> Currently, this code yields:
>
> Error: destructor `A.~this` cannot be used because it is annotated with @disable
>
> I was expecting that disabling the destructor would make it as if the struct does not have a destructor

Why? That's not the semantics of @disable. And why would you want that? What are you actually trying to achieve?

> , instead it makes the program not compile. I find this behavior odd: why not make it illegal to disable the destructor if disabling it will surely result in errors wherever the struct is used.

Because it won't surely result in errors wherever the struct is used ... you yourself provide an example below where it doesn't.

 The only
> situation where the code will compile is A is never used directly.

Eh? You immediately give a contrary example:

> To make matters even more confusing, this code compiles:
>
> class A
> {
>     int a;
>     @disable ~this() {}
> }
>
> void main()
> {
>     A a = new A();
> }

Why is that confusing? Why shouldn't it compile? The A that you created is on the heap, so its destructor is never invoked, so what would cause it not to compile?

>
>
> So, is this a bug or am I missing something?
>
> Yoroshiku onegaishimasu,
> RazvanN


July 19, 2018
On Thursday, 19 July 2018 at 09:50:32 UTC, Jim Balter wrote:
> On Thursday, 19 July 2018 at 08:50:15 UTC, RazvanN wrote:
>> struct A
>> {
>>     int a;
>>     @disable ~this() {}
>> }
>>
>> void main()
>> {
>>     A a = A(2);
>> }
>>
>> Currently, this code yields:
>>
>> Error: destructor `A.~this` cannot be used because it is annotated with @disable
>>
>> I was expecting that disabling the destructor would make it as if the struct does not have a destructor
>
> Why? That's not the semantics of @disable. And why would you want that? What are you actually trying to achieve?

I just don't understand why you would ever mark the destructor of a struct with @disable. When is that useful? If it's not, why not just forbit it?

July 19, 2018
On Thursday, 19 July 2018 at 10:04:34 UTC, RazvanN wrote:
> I just don't understand why you would ever mark the destructor of a struct with @disable. When is that useful? If it's not, why not just forbit it?

struct S1 {
    ~this() { /* stuff */ }
}

struct S2 {
    S1 s;
    @disable ~this();
}

The idea would be that S1's destructor not be called when S2 goes out of scope. Now, that's not how @disable works, but it's a logical thought.

The way @disable does work though, isn't to remove the marked function, but forbid it from being called.

> why not make it illegal to disable the destructor if disabling it will surely result in errors wherever the struct is used.

Because the error message when you use it clearly states what's wrong?

It's actually possible to use a struct with a @disabled destructor:

struct S {
    int i;
    @disable ~this() {}
}

struct Nodestruct(T) {
    ubyte[T.sizeof] _payload;
    @property
    ref T value() {
        return *cast(T*)_payload.ptr;
    }
}

The trick is, as you can see, to never have an instance on the stack. This gives a small advantage over @disable this(this) and @disable this() in that it's actually impossible to have a stack-allocated instance.

--
  Simen
July 19, 2018
On Thursday, July 19, 2018 10:04:34 RazvanN via Digitalmars-d-learn wrote:
> I just don't understand why you would ever mark the destructor of a struct with @disable. When is that useful? If it's not, why not just forbit it?

There's nothing special about destructors here. You can @disable any member function, and if you do, you get an error if you try to use it, since it's @disabled. So, code that doesn't use an @disabled function works just fine, and any code that attempts to use it gets an error. For the vast majority of functions, @disabling them really doesn't make any sense, but from what I can tell, @disable was simply implemented as a general feature rather than trying to allow specific functions to be @disabled and then have to add code for each function that we want to be able to @disable. So, the fact that you can @disable destructors is just the result of the feature being implemented in a simple, straightforward manner. But while I agree that @disabling destructors doesn't make sense, I don't see why it would actually be a problem that it's allowed. Anyone who tries it is just going to quickly get errors and have to remove @disable from the destructor. Explicitly make it illegal to mark a destructor with @disabled doesn't really add anything from what I can see.

- Jonathan M Davis

July 20, 2018
On Thursday, 19 July 2018 at 10:04:34 UTC, RazvanN wrote:
> On Thursday, 19 July 2018 at 09:50:32 UTC, Jim Balter wrote:
>> On Thursday, 19 July 2018 at 08:50:15 UTC, RazvanN wrote:
>>> struct A
>>> {
>>>     int a;
>>>     @disable ~this() {}
>>> }
>>>
>>> void main()
>>> {
>>>     A a = A(2);
>>> }
>>>
>>> Currently, this code yields:
>>>
>>> Error: destructor `A.~this` cannot be used because it is annotated with @disable
>>>
>>> I was expecting that disabling the destructor would make it as if the struct does not have a destructor
>>
>> Why? That's not the semantics of @disable. And why would you want that? What are you actually trying to achieve?
>
> I just don't understand why you would ever mark the destructor of a struct with @disable. When is that useful?

I don't know, but that doesn't mean there's no possible reason to.

> If it's not,

We haven't established that it's never useful. When you pose a conditional like that, it's a logical mistake to just assume that the condition is met.

> why not just forbit it?

Because the compiler shouldn't be littered with pointless special case restrictions that have to be maintained and might interfere with a valid use case that you haven't thought of. The fact is that you disabled the destructor, then invoked the destructor, and got a clear, informative error at the point of invocation, rather than at the @disable. This is, IMO, a cleaner, better design than the one you're asking for.

And it's not true that you "just" don't understand why one would ever @disable the destructor ... in your original post you asked "why not make it illegal to disable the destructor if disabling it will surely result in errors wherever the struct is used" -- it was pointed out that it *doesn't* "surely result in errors wherever the struct is used" -- it only results in an error if the destructor is invoked, exactly as one would expect. In your original post you claimed "The only situation where the code will compile is A is never used directly" -- it was pointed out that this isn't true, as your own example showed. In your original post you said that it was confusing that code that you had just erroneously stated wouldn't compile does compile, and it was pointed out that there's no reason why it shouldn't compile and there's no apparent reason to find it confusing. In your original post you asked if that's a bug, and it has been pointed out that it's not a bug. I hope everything is clear now and all your questions have been answered.

July 20, 2018
On 7/19/18 4:50 AM, RazvanN wrote:
> struct A
> {
>      int a;
>      @disable ~this() {}
> }
> 
> void main()
> {
>      A a = A(2);
> }
> 
> Currently, this code yields:
> 
> Error: destructor `A.~this` cannot be used because it is annotated with @disable
> 
> I was expecting that disabling the destructor would make it as if the struct does not have a destructor, instead it makes the program not compile.

That's a misunderstanding of @disable. @disable *defines* the function, and makes it uncallable.

If you want a struct without a destructor, just don't define one. Or if you want one that eliminates the default destructor (in the case where you have members with dtors), define an empty destrutor.

-Steve