Default initialization no longer a thing

Jonathan M Davis newsgroup.d at jmdavisprog.com
Mon Oct 23 21:37:51 UTC 2023


On Monday, October 23, 2023 12:54:45 PM MDT IGotD- via Digitalmars-d wrote:
> I've recently seen that modern program languages are going away
> from default initialization. D early recognized no initialization
> being one of the many flaws in C/C++ and added default
> initialization which greatly improved stability which has been
> the standard for many languages since. C++ "fixed" this very
> recently but really not.
>
> Now even more modern languages are going away from default
> initialization as some claim that default initialization was a
> source of bugs. The implementation might differ, some must give a
> variable a value at declaration others detect use before assign.
>
> What is your take on this and if D would ever be modernized, is
> this something that D should consider?

Default initialization is too baked into D for it to change at this point,
and there are features that we have which you can't have without it (at
least not without having objects being garbage, because they haven't been
given a value yet). It's why disabling default initialization on structs can
be quite annoying, since it results in them not working in a number of
places (particularly with regards to arrays).

In general though, if you want to avoid issues with objects being used
before they're properly initialized, you have two options:

1. Have default initialization so that it's guaranteed that the object will
have a value even if it's ever used before it has the value that you want it
to actually have.

2. Make the compiler smart enough to catch when a variable is used before
it's initialized and make it an error, thereby forcing explicit
initialization of all variables before they're used.

The second approach works in a number of cases, but inevitably, the compiler
is not smart enough to correctly determine whether a variable has actually
been initialized in all cases, forcing you to give it a value when it
shouldn't be necessary (this is something that can happen in Java quite
easily). And it's _not_ something that is actually fully solvable, because
it's possible that whether a variable has been initialized yet or not
depends on runtime logic which is affected by stuff outside of that
function, which the programmer is aware of, but the compiler can't be due to
separate compilation (though arguably, if the logic is separated enough from
the variable's initialization, it should be given a value regardless just to
be safe, since the other code could change without the variable's
initialization code being altered appropriately).

It becomes easier for the compiler if you simply require that the variable
be given a value when it's declared, but that arguably just makes the
problem worse, because then you're forced to give the variable a value
before you want to in any situation where you need to declare it before
giving it the actual value that you want to give it. And ultimately, it
results in the programmer manually doing what default initialization would
have done and give the variable a value that they don't actually want to use
but which will at least not be garbage.

However, arguably, an even bigger issue is initialization that doesn't
necessarily involve a variable. For instance, you could have something like

auto arr = new int[](10);

or

foo(new int[](10));

In D, all of the array's elements are default-initialized to the init value
of the element type, so no garbage is involved, but what if you had no
default initialization? You'd be forced to do something like

auto arr = new int[](10, value);

and set all of the elements in the array to some programmer-provided value,
which really isn't any better than using a default value and might even
be less efficient given that the compiler knows the type's init value at
compile time, but it wouldn't know what the value would be if it's provided
at runtime.

Various other aspects of arrays also depend on the default value and really
can't be done without it. E.G.

arr.length += 20;

isn't going to work without a default value. Without that, you'd be forced
to append or use a different syntax that provided your own value to use as
the default before you go and assign it what you actually want it to be
later.

Default values also make implementing the logic in user-defined types easier
and safer (especially in classes with inheritance), because the compiler can
rely on everything having an actual value before the constructors run.
Having something like immutable does actually force you to implement a lot
of the same logic that you'd have to have without default initialization, so
D can't simplify how constructors work with regards to code flow analysis
quite as much as might be nice, but a language without immutable or const
could forgo a lot of the code flow analysis that languages typically have to
do for constructors in the face of inheritance, because it could know that
the member variables wouldn't be garbage. With D, the compiler knows that
they're not garbage but has to make sure that it doesn't reassign values to
any const or immutable member variables.

There are certainly cases where default-initialized objects can be a problem
(e.g. when you end up with a null pointer or reference), and in some cases,
having default values can be problematic (which is why the ability disable
default initialization was added to structs in D), so there's certainly an
argument for requiring initialization in some cases rather than relying on a
default value, but in general, having default values for all types is far
more flexible than requiring that the compiler track whether a variable is
initialized before it's used. So, I think that D made the right choice, but
it's not particularly surprising if a number of the newer languages out
there have made a different choice.

Ultimately though, I don't think that it's possible to prevent bugs with
regards to initializing variables with default values that shouldn't
actually be used, because even if you don't have default values in the
language, there will always be cases where programmers have to give a
variable a default value of some kind anyway, because the compiler can't
always correctly determine whether a variable is used before it's
initialized if it allows deferring initialization (and if it doesn't allow
defering initialization, then you'll end up with user-decided default values
that much more frequently).

- Jonathan M Davis





More information about the Digitalmars-d mailing list