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.