Structs are Not Plain: A call for empty struct constructors

Jonathan M Davis newsgroup.d at jmdavisprog.com
Thu Sep 19 20:25:53 UTC 2019


On Thursday, September 19, 2019 3:02:39 AM MDT FeepingCreature via 
Digitalmars-d wrote:
> I think the deeper problem stems right from the original
> assumption that structs are "plain old data" and thus shouldn't
> be interested in construction. With their use in reference
> counting, with(), destructors, assignments... does anyone still
> really believe that? Structs have taken on a dual role of "plain
> old data, and also anything that needs customized behavior bound
> to lifecycle."
>
> The decision to not allow `this()` stems from a time where that
> wasn't really on the table, and I think it should be overturned.
> Let `Struct s;` be Struct.init, by all means, but `Struct()`
> should call `this()`, if there is one.

This has nothing to do with structs being POD. It has to do with how D was
designed with the idea that every type has an init value which is known at
compile time, and various operations rely on being able to simply blit that
init value. Having default constructors would mean that none of that code
could simply blit the init value but would instead have to construct the
structs using the default constructor. It also could no longer rely on
having a default value which works at compile time. If you want to see how
much in D relies on the init value working, then @disable default
initialization on a struct and see how much it doesn't work with. Having
@disable this(); was hacked into the language later, and there's plenty of
stuff that doesn't work when it's used (e.g. dynamic arrays won't work at
all with types that can't be default-initialized, because they rely on being
able to blit the init value).

Classes avoid all of this, because they have an extra layer of indirection,
and T.init is the init value for T's reference, meaning that it can just be
null, whereas because structs can live directly on the stack, default
initialization requires initializing the struct itself.

Default construction of structs was a casualty of D's goal of avoiding
objects being initalized as garbage like you get in C/C++. It certainly can
be annoying at times, but in most cases, you can just use a factory function
instead, and if you want to avoid such a struct ever accidentally being used
via its init value instead of the factory function, then disable default
initialization for that type. And for a use case like you're talking about
here where you're using RAII without needing to actually put the object
inside of a container (or anything else that would require the init value),
it should work just fine. You'll just get something like

with(Fixture.make())
{
}

or

with(Fixture.cons())
{
}

or whatever instead of

with(Fixture())
{
}

Adding default construction to the language would be a pretty big change,
and I expect that you would need a DIP going over all of the pros and cons,
taking into account exactly how the language relies on init in order to get
it changed. Given how baked into the language init is, my guess is that such
a DIP doesn't stand much of a chance, but I don't know.

- Jonathan M Davis





More information about the Digitalmars-d mailing list