Struct no-arg constructor?

monarch_dodra monarchdodra at gmail.com
Wed Jul 25 02:34:12 PDT 2012


According to TDPL, the rationale for structs not having default 
constructors is "T.init", were T.init is defined as:
*A static, known at compile time, mem-copyable value.
*The value that gets mem-copied into structs before the 
constructors are called
*The value that gets mem-copied into structs when moving stuff 
out of them.
**Destructors must support being called on a T.init element.

The thing is, I can't, for the life of me, understand how that 
interferes with having a default constructor. Wouldn't keeping 
the current definition of init, but allowing a call to a "no-arg" 
constructor after after the mem-copy of T.init also work? As long 
as the destructor keeps supporting calls to T.init objects, then 
all is fine. Why hold out on a very useful functionality?

Am I missing a case where having a default constructor could 
actually mess things up? The restriction just feels gratuitous 
for me.

----------------------------------------------------------------
----------------------------------------------------------------

This has been bringing me problems recently, with structs that 
need to allocate data, but don't really require any meaningful 
arguments to passed to them at construction. Array is a perfect 
example of the kind of struct I'm talking about. To force 
initialized them, I have the choice of:
*Forcing a call to an "initialize" manually: No way of 
enforcement at client side.
*Putting a call to "initialize" inside EACH AND EVERY function. 
Inefficient and error prone.
*Enforce the use of a factory.
Not only is all the above far from perfect, it really pushes me 
to use a "two pass" initialization scheme (we all know how 
horrible those are), but what makes it the worse is that it feels 
the language could handle this just fine.

The tipping point for me was investigating a bug with Array, 
which led me into RefCounted:

----
alias RefCounted!(int, RefCountedAutoInitialize.yes) RCIAI;
void main() {
     alias RefCounted!(int, RefCountedAutoInitialize.yes) RCIAI;
     RCIAI a;
     a = 5
}
----

You know what this does? An access violation. Do you know why? 
Because at this point, a, of type "autoAnitialize.yes" ISN'T 
initialized! WTF, right? This is actually a bug inside opAssign, 
which *should* enforce initialization (when the static type is 
autoInitialize.yes, of course). A bug fix I will be pushing soon.

But this is just a partial fix: The truth is that the next 
snippet will plain and simply NEVER work. EVER. Never Ever. No 
matter what we do.

----
RCIAI a;
RCIAI b = a;
b = 5;
writeln(a);
----

While one might think that a should hold the value "5", NOTHING 
in this snippet even has the potential of touching a, until we 
get to the last line, and call the "alias refCountedPayload 
this;" function (inside writeln). At this point, a has forgotten 
all about b.

You might be thinking: Cute, but that works as expected, a is a 
reference counted object. Maybe.

But the same behavior will happens to ALL structs. Would this be 
the expected behavior for Array?


More information about the Digitalmars-d mailing list