Struct initialization is a mess

H. S. Teoh hsteoh at quickfur.ath.cx
Wed Jul 28 23:43:25 UTC 2021


On Wed, Jul 28, 2021 at 11:08:34PM +0000, Dukc via Digitalmars-d wrote:
[...]
> void main()
> { {Basic a, b = Basic.init, c = Basic(), d = {}, e = Basic(0), f = {0};}
>   {NoDef /*a,*/ b = NoDef.init, /*c = NoDef(), d = {}, e = NoDef(0),*/ f =
> {0};}
>   {FalseInit a, /*b = FalseInit.init,*/ c = FalseInit(), d = {}, e =
> FalseInit(0), f = {0};}
>   {Ctor a, b = Ctor.init, c = Ctor(),/*, d = {}*/ e = Ctor(0)/*, f = {0}*/;}
>   {EmptyOpcall a, b = EmptyOpcall.init, c = EmptyOpcall(), d = {}, /*e =
> EmptyOpcall(0)*/ f = {0};}
>   {ArgumentedOpcall a, b = ArgumentedOpcall.init, /*c =
> ArgumentedOpcall(),*/ d = {}, e = ArgumentedOpcall(0), f = {0};}
> }
> ```
> 
> We have terribly many ways to initialize a struct (or union or class
> for that matter). I have trouble seeing the logic between all these.

I'm having trouble seeing why these are problematic.  It basically just
boils down to a couple of cases:

1) No initialization / initialize with a struct instance: just declare
the variable, optionally assigning an instance of the struct (in this
case, .init). This is normal and expected.  Note that initializing with
opCall falls under this category.

2) Initialize with brace syntax. This is one of the ways of initializing
a struct.

3) Initialize with constructor syntax. This is the other way of
initializing a struct.

That's pretty much it.

The only wrinkle in this picture is the interaction between .init and
@disable this().  Historically, before @disable was introduced to
language, ALL types have an .init value. It was something generic code
could rely upon to get an instance of any type.

Somewhere along the line, somebody twisted Walter's arm to add @disable,
to paper over the existence of .init by making it illegal to declare an
instance of a type without explicitly constructing it.  Unfortunately, a
LOT of things in the language and its ecosystem had come to rely upon
.init by then, and .init is so deeply entrenched in the compiler (and
the language) that AFAIK it still exists in its innards somewhere even
for ostensibly no-default-construction types.  I.e., @disable doesn't
*completely* disable .init, it just hides it away (or tries to -- and
not very completely, as you discovered).

Compounding this imperfect implementation of @disable is:

	https://issues.dlang.org/show_bug.cgi?id=7597

which is a long-standing issue (IMO bug) where users can willy-nilly
declare their own definition of .init and thereby cause all sorts of
pathological behaviour in the compiler & any code that relies upon .init
to mean what it's supposed to mean.


So there you have it, (1), (2), and (3) are the basic cases from which
everything else derives.  The weird cases are caused by compiler bugs
and incomplete/imperfect implementation of @disable and its
unexpected/unwanted interactions with .init.


T

-- 
I am a consultant. My job is to make your job redundant. -- Mr Tom


More information about the Digitalmars-d mailing list