struct parameterless constructor
H. S. Teoh
hsteoh at qfbox.info
Mon Aug 4 23:21:53 UTC 2025
On Mon, Aug 04, 2025 at 08:02:48PM +0000, Brother Bill via Digitalmars-d-learn wrote:
> I feel like I am going into the hornet's nest with this discussion.
You are. ;-)
> I have created a struct with some members, and want to have a
> parameterless constructor that sets the member values at run time.
This will be running up against a wall. It's possible to scale it, but
it will require effort.
> I have seen things like @disable this(); and static opCall(), but
> don't quite understand them.
First you need to understand why D is the way it is. In the original
design, complex objects that require non-trivial construction were
intended to be class objects. They would support inheritance and
polymorphism and the other standard OO idioms, and they require a
constructor. That's why the compiler will not generate a default class
ctor for you: construction of a class object is expected to be
non-trivial and require work from the coder to initialize correctly. You
were expected to write the default ctor yourself to put the object in
the correct initial state.
Structs, OTOH, were intended to be "glorified ints": i.e., they are
by-value types intended to be cheap to copy, and to have a default state
(the .init state) that's known at compile-time and can be simply blitted
(copied bit-for-bit) from a template known at compile-time and would be
in a valid initial state. IOW, just like ints. Therefore, parameterless
default ctors are *not* supported: instead, you'd just specify initial
field values in the struct declaration:
```
struct S {
int x = 123;
float y = 3.14159;
}
```
The compiler would store the initial values (123, 3.14159) in a
read-only struct template that it simply memcpy()'s over every time it
needs to initialize an instance of S. It was intended that this was the
only initialization needed, so the language did not support default
ctors for structs.
//
Fast forward 20 or so years, and things have changed a bit. People
started using structs for many other things, some beyond the original
design, and inevitably ran into cases where they really needed
parameterless default ctors for structs. But since the language did not
support this, a workaround was discovered: the no-op default ctor that
the compiler generates for each struct (i.e., this()), was tagged with
@disable, which is a mechanism to indicate that the initial by-value
blit of the struct is *not* a valid initial state. Then opCall was used
so that you could construct the struct like this:
auto s = S();
which resembles default construction for class objects, at least
syntactically. This wasn't in line with the original design of the
language, but it worked with current language features and got people
what they wanted without further language changes, so it was left at
that, and became the de facto standard workaround for the language's
lack of default struct ctors.
> How does one do this, and what are the ramifications of doing so?
> Or should one just leave the parameterless constructor as is?
If you were to ask me, I'd say generally your code will experience less
friction with the language if you just went along with the original
design of structs being "glorified ints" instead of fighting with the
language all the time. This will generally lead to less unexpected
problems that you might run into if you use the @disable/opCall hack,
esp. where generic code is concerned.
Generic code often assumes that T.init gives you a valid instance of a
type T, but with types that @disable the default ctor and use opCall to
construct instances, this is no longer true so some generic code may not
work with your type.
Also, generic code may also assume that they can just declare a variable
of type T and assign a value to it later, but with a @disable'd default
ctor, this will fail to compile. This may sometimes lead to several
pages long compile errors from deep inside some private internal
component of a generic API, that are often hard to understand because
it's not immediately obvious why it refuses to compile. Since
metaprogramming / generic code is one of D's (very) strong points, this
situation is generally undesirable, unless you prefer writing
C/C++-style code in D instead of idiomatic D code.
Having said all that, though, some use cases simply demand default
struct construction; in such cases, you have no choice but to work with
the @disable/opCall hack.
T
--
Written on the window of a clothing store: No shirt, no shoes, no service.
More information about the Digitalmars-d-learn
mailing list