On Thursday, 29 August 2024 at 14:28:09 UTC, Ogi wrote:
>This has been discussed ad nauseam, so I’m skipping rationale. Let’s just say that many users want this feature, especially those who need C++ interop. Here’s how it can be implemented in a non-problematic way.
A struct with a default constructor can only be instantiated by an [explicit] constructor call, following the same rules as a struct with a disabled default constructor.
I dislike the requirement to explicitly construct. I don't see the drawback of implicit construction.
>struct S {
this() {
writeln("S.this()");
}
}
void main {
S s; // error
S t = S(); // ok (constructed by calling `S.this()`)
S u = void; // ok (not `@safe`)
S v = S.init; // ok (may be a logically incorrect object)
S[3] a; // error
S[3] b = [S(), S(), S()]; // ok
}
The array example is so bad...
>If any fields of an aggregate type are structs with default constructors, all constructors of this type must initialize them. If a default constructor is not defined, default construction is disabled.
struct S {
this() { writeln("S.this()"); }
}
struct T {
S s;
// implicit `@disable this();`
}
Why not implicit:
this() {
s = S();
}
> struct U {
S s;
this(int x) {} // error: `s` must be initialized
this() { s = S(); }
}
class C {
S s;
this(int x) {} // error: `s` must be initialized
this() { s = S(); }
}
Seems fine
But what happens in this case?
struct S
{
this(int) {}
}
S s; // ok?
Seems like if you want to require constructor calls when they are present, it should be consistent.
This is a different approach than what I posted here. I'm approaching it from the side of hooking default initialization, whereas you are approaching it from the side of disallowing default initialization.
Note that with the advent of editions, we can do whatever we want with semantics, and given that default constructors do not currently exist, keeping existing behavior when they are not present seems reasonable to me.
-Steve