September 05

On Thursday, 5 September 2024 at 17:46:18 UTC, Quirin Schroll wrote:

>
  • Deprecate init. Replace it with default(T) (read: “default of T”) which gives you an uninitialized object of type T that might or might not be usable. It can’t be hooked (unlike init) because default is a keyword. A constructor transforms a the default(T) object into an object that satisfies the invariants of T if any. In general, using default(T) is a bad idea unless you do it knowing full well what you’re getting.

Wouldn't it be easier to just forbid user-defined .init properties? It's a breaking change either way.

>
  • A default constructor is only implicitly present if all data members have a default constructor and no constructor is explicitly defined.

Would this also apply if some members have default constructors and the others are things like integers or POD structs?

>
  • A default constructor can be explicitly set to be the generated one using default: default this();

We already have compiler-generated default implementations for copy constructors and opAssign, and neither of them support this kind of explicit declaration. Why is it necessary to have this for default constructors, if it wasn't necessary for copy constructors and opAssign?

September 06

On Thursday, 5 September 2024 at 18:17:33 UTC, Paul Backus wrote:

>

On Thursday, 5 September 2024 at 17:46:18 UTC, Quirin Schroll wrote:

>
  • Deprecate init. Replace it with default(T) (read: “default of T”) which gives you an uninitialized object of type T that might or might not be usable. It can’t be hooked (unlike init) because default is a keyword. A constructor transforms a the default(T) object into an object that satisfies the invariants of T if any. In general, using default(T) is a bad idea unless you do it knowing full well what you’re getting.

Wouldn't it be easier to just forbid user-defined .init properties? It's a breaking change either way.

>
  • A default constructor is only implicitly present if all data members have a default constructor and no constructor is explicitly defined.

Would this also apply if some members have default constructors and the others are things like integers or POD structs?

In principle, yes. If every data member’s type T supports T(), I consider it having a default constructor. The reason why T() works is irrelevant, maybe excluding static opCall.

> >
  • A default constructor can be explicitly set to be the generated one using default: default this();

We already have compiler-generated default implementations for copy constructors and opAssign, and neither of them support this kind of explicit declaration. Why is it necessary to have this for default constructors, if it wasn't necessary for copy constructors and opAssign?

Because defining any constructor makes the compiler not generate a default constructor. It’s a way to say: Give me the default constructor without spelling it out. Maybe I’m leaning too much into the C++ direction, and this() {} would absolutely work. But generally, default this(); would make the default constructor have attributes and this() {} would not. If that’s the only difference, it maybe isn’t worth it.

September 06

On Friday, 6 September 2024 at 09:45:39 UTC, Quirin Schroll wrote:

>

On Thursday, 5 September 2024 at 18:17:33 UTC, Paul Backus wrote:

>

We already have compiler-generated default implementations for copy constructors and opAssign, and neither of them support this kind of explicit declaration. Why is it necessary to have this for default constructors, if it wasn't necessary for copy constructors and opAssign?

Because defining any constructor makes the compiler not generate a default constructor. It’s a way to say: Give me the default constructor without spelling it out.

My point is: so far, we have been fine with requiring the programmer to spell it out in other cases. Why is that unacceptable in this case specifically?

Maybe the answer is, "it's not just a problem in this case, the programmer shouldn't have to spell it out in any of those other cases either." If so, then this should be a more general language feature, with its own DIP separate from any default-constructor proposal.

September 08

On Thursday, 5 September 2024 at 17:46:18 UTC, Quirin Schroll wrote:

>

C++ has had default constructors forever. It’s one of the few decisions where I’m convinced that C++ got it right and D isn’t. “Variable declarations must be cheap” is a dogma that I’d expect in a language like C or Zig, not in a language like D, where frequently, safety wins over performance. The fact that I can declare a variable in D and it might not be safe to use is a problem.

Apparently Zig is also about to adopt .init/.default/.empty during variable declaration. Even if there is no ctor/dtor (RAII).

https://ziggit.dev/t/prefered-method-to-initialize-generalpurposeallocator/5875/13

September 13

On Sunday, 8 September 2024 at 00:00:49 UTC, Matheus Catarino wrote:

>

On Thursday, 5 September 2024 at 17:46:18 UTC, Quirin Schroll wrote:

>

C++ has had default constructors forever. It’s one of the few decisions where I’m convinced that C++ got it right and D isn’t. “Variable declarations must be cheap” is a dogma that I’d expect in a language like C or Zig, not in a language like D, where frequently, safety wins over performance. The fact that I can declare a variable in D and it might not be safe to use is a problem.

Apparently Zig is also about to adopt .init/.default/.empty during variable declaration. Even if there is no ctor/dtor (RAII).

https://ziggit.dev/t/prefered-method-to-initialize-generalpurposeallocator/5875/13

As I read the thread, it’s specific to GeneralPurposeAllocator and other structs for which compile-time default initialization can’t be done. Zig’s init is a fully formed object that is a run-time-initialized value specifically crafted for each type that has it, very much unlike D’s inits.

Part of Zig’s dogma is that everything that happens has to be explicit. Technically, there are no destructors in Zig, just functions you’re supposed to call after an object isn’t needed anymore, which you normally do using defer. The difference is, every use of an object requires a defer deinit();, i.e. there is no implicit destructor call. In D, we’re comfortable with destructors and other implicit stuff, so a declaration implicitly calling a default constructor is very much in line with what D does elsewhere. It’s not even close to being that implicit as a destructor call, actually.

“Make interfaces easy to use correctly and hard to use incorrectly.” ―Scott Meyers https://www.aristeia.com/Papers/IEEE_Software_JulAug_2004_revised.htm

A struct type for which S s; s.f(); doesn’t really work, but S s = S(); s.f(); is bad design.

September 18

On Friday, 30 August 2024 at 15:17:06 UTC, Steven Schveighoffer wrote:

>

On Thursday, 29 August 2024 at 16:44:46 UTC, Nick Treleaven wrote:

>

Should we make S() for any struct an error in the next edition?

I have a bold suggestion instead -- let's just start having default constructors.

What's stopping us? We are on the cusp of ridding ourselves of magic runtime hooks, they are all now becoming templates.

For instance, setting the length of an array now calls a template and that template could just call the default constructor if it exists.

Then this whole mess of what S() means vs S.init, or whatnot becomes much more sane.

It's something we should start thinking about and discussing.

-Steve

+1 for default constructor

1 2
Next ›   Last »