D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 22562 - Spec for default initialization is self-contradicting wrt. nested structs
Summary: Spec for default initialization is self-contradicting wrt. nested structs
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dlang.org (show other issues)
Version: D2
Hardware: All All
: P4 enhancement
Assignee: No Owner
URL:
Keywords: spec
Depends on:
Blocks:
 
Reported: 2021-12-03 13:12 UTC by Stanislav Blinov
Modified: 2024-12-15 15:27 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Stanislav Blinov 2021-12-03 13:12:29 UTC
The current spec uses .init and "default initializer" interchangeably:

https://dlang.org/spec/property.html#init
https://dlang.org/spec/type.html#basic-data-types (in table header - "Default initializer (.init)").

In the first link, it also explicitly states that .init for a nested struct contains null context pointer.

However, these following sections...

https://dlang.org/spec/struct.html#default_struct_init
https://dlang.org/spec/struct.html#default_union_init

...state that:
"Struct/union fields are by default initialized to whatever the Initializer for the field is, and if none is supplied, to the default initializer for the field's type."

Then it follows that, if field initializer isn't supplied, that field is initialized to its .init (i.e. the default initializer). Which is not what happens when nested structs are involved.

Consider this code:

void main()
{
    int a;
    struct Nested { void foo() { ++a; } }
    static struct Holder { Nested n; }
    union Wrapper { Nested n; }
    Nested n;
    Holder h;
    Wrapper w;

    assert(n.tupleof[$-1]);
    assert(h.n.tupleof[$-1]);
    assert(w.n.tupleof[$-1]);
}

All asserts pass. Which means that neither n nor h.n nor w.n are initialized with default initializer. If https://dlang.org/spec/property.html#init is correct, .init and "default initializer" are one and same, and .init of nested structs contains null context pointer, then:

If a context pointer of n (which is a field, albeit hidden) was to be default-initialized per field initialization spec (https://dlang.org/spec/struct.html#default_struct_init), it would've been set to null.

If h.n was to be default-initialized per field initialization spec (https://dlang.org/spec/struct.html#default_struct_init), its context pointer would've been set to null.

If w.n was to be default-initialized per union initialization spec (https://dlang.org/spec/struct.html#default_union_init), its context pointer would've been set to null.

I.e. all three asserts should've failed. Yet they pass, which means either initializations of those three variables violate the spec, or the spec contradicts itself.

To remove this contradiction, the spec should explicitly define whether .init is "default initializer", and explicitly address default initialization of nested structs (including when they are fields in other aggregates).

There may be a worthwhile language enhancement whereby all nested structs should have implicitly disabled `this()`. Such behavior is already partially enforced by the compiler, when nested struct appears as a field of a struct defined outside of nested struct's parent:

struct Container(T)
{
    T value;

    // following line yields Error: field `value` must be initialized in constructor, because it is nested struct
    this(Args)(auto ref Args)
    {
        /* ... */
    }
}

void main()
{
    int a;
    struct Nested { void foo() { ++a; } }
    Container!Nested cont = 3;
}
Comment 1 dlangBugzillaToGithub 2024-12-15 15:27:14 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dlang.org/issues/4120

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB