Default struct constructor

Jonathan M Davis newsgroup.d at jmdavisprog.com
Fri Feb 8 08:25:18 UTC 2019


On Thursday, February 7, 2019 8:02:09 AM MST bitwise via Digitalmars-d 
wrote:
> On Wednesday, 6 February 2019 at 23:17:31 UTC, Jonathan M Davis
>
> wrote:
> > On Wednesday, February 6, 2019 7:49:28 AM MST bitwise via
> >
> > Digitalmars-d wrote:
> >> [...]
> >
> > If that's what you want, then you can just use a static opCall.
> > e.g.
> >
> > struct S {
> >
> >     static S opCall() { ... }
> >
> > }
> > auto s = S();
> >
> > The only real restriction is that you can't declare any
> > constructors if you have any static opCall functions declared.
> >
> > - Jonathan M Davis
>
> Sorry - my example was pretty bad.
>
> I'm suggesting that this(void) be a dynamic alternative to T.init.
>
> Current:
>
> struct S { int n; }
> S s = void;
> s.n = 1;
>
> Suggested:
>
> struct S { int n; this(void){ n = 1; } }
> S s;   // this(void) invoked here and T.init not used

So, basically, you want default constructors but are suggesting that there
be an explicit void parameter in the declaration to indicate that that's
what you're doing rather than just having it not have any parameters. Well,
that runs into all of the problems related to the fact that D was designed
around the idea that everything is default-initialized. It's not an
impossible hurdle, but it would be a significant shift in how the language
works, and it would mean that stuff like how arrays are initialized would
change drastically depending on the types involved, whereas right now, you
need default initialization, or you simply can't use the type in an array,
and the way that arrays are initialized is the same for all types. It also
would be a problem from the standpoint of code clarity. With something like

S s = void;

you can clearly see that the programmer has explicitly requested that the
variable not be properly initialized, whereas with your suggested default
constructors, suddenly you would no longer know what

S s;

did unless you looked at the type. In the vast majority of cases, it would
be default-iniatialized, but occasionally, it would be default constructed,
and that could cause quite a bit of confusion.

It also still doesn't get around the fact that _all_ types in D have an init
value, and someone could use it (e.g. std.algorithm's move function uses it
to give the old variable a valid value rather than garbage after the move).
Even types which have disabled default initialization have init values. And
it would be very disruptive to the language to try to change that if it's
really possible it all (e.g. objects are always initialized to their init
value before any constructors are run, so the way that constructors work in
D relies on there being an init value for the type). So, with how D is
designed, you really can't rely on a constructor having been run for a
struct object. It can be made much harder to not have called a constructor
(e.g. by using @disable this();), but as long as the init value exists,
there's a way around the constructor. So, fundamentally, I really don't see
how default constructors for structs can fully work in D. At best, it could
be made to work in the common cases and even that's only possible by
complicating how a number of core things work so that they do different
things depending on whether a struct is default constructed or default
initialized, which would definitely complicate the language.

Honestly, I really think that trying to make default constructors work in D
is a mistake. Default initialization and init are just too baked into the
language. Even trying to create a type with @disable this(); is pretty
questionable. It's useful in rare situations, but it has to be handled with
care - particularly since the type's init value still exists, and some code
will use it.

It's true that there are use cases where the lack of a default constructor
for structs is annoying, but in general, all you have to do is use a factory
method instead and then make sure that the type still works if its init
value is used (e.g. make sure that the destructor is aware that the factory
method can be bypassed). And if you absolutely must have default
construction, you can always use a class instead.

- Jonathan M Davis





More information about the Digitalmars-d mailing list