tip: use union to manually control struct member destructor

Posted 2021-03-15

Also I finally implemented simpledisplay's takeScreenshot function. Only 4 years late.

Core D Development Statistics

In the community

Community announcements

See more at the announce forum.

What Adam is working on

On arsd master, simpledisplay's takeScreenshot method is now implemented (finally! I added the interface in 2017...) and the Sprite class now offers arguments to draw just part of the image, useful for slicing up spritesheets.

Tip of the Week

If you have a struct member with a @system destructor in your other struct, but you want to make it @trusted, you need to use a union trick:

struct A {
	~this() @system {}
}

struct B {
	// single-member union gives manual control over dtor
	union { A a; }
	~this() @trusted {
		// so now I can do this in the trusted wrapper
		.destroy(a);
	}

	// downside is other auto-generated niceities
	// like opEqual etc are also manual control now too.
	//
	// So you may need to implement other methods as well yourself.
}

void main() @safe {
	B b; // this is now allowed, without the union trick this would error.
}

This works because of the clause in the spec: https://dlang.org/spec/struct.html#struct-destructor

Unions may have fields that have destructors. However, a union itself never has a destructor. When a union goes out of scope, destructors for it's fields are not called. If those calls are desired, they must be inserted explicitly by the programmer

Normally, destructors are called automatically in sequence - it is not inserted in your own destructor, but rather the compiler generates a super-destructor that calls yours as well as the member ones. Using this union trick suppresses the compiler's automatic handling of the member so you can do it yourself.

Just be warned that it is entirely trusting you to do it right!