Disallowing S() when struct S has a constructor

Jonathan M Davis newsgroup.d at jmdavisprog.com
Fri Aug 30 16:32:21 UTC 2024


On Friday, August 30, 2024 9:17:06 AM MDT Steven Schveighoffer via Digitalmars-
d 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.

I don't know. Initialization is just simpler if default constructors aren't
a thing. Occasionally, it would be really nice to have them, but the vast
majority of the time, they're simply not needed. And there's a _lot_ of D
code written with the assumption that they're not a thing. It's already
problematic that we added the ability to disable default initialization,
since most code tends to assume that that isn't really a thing, and it
creates annoying corner cases. Similarly, the fact that types can declare an
init member just causes problems, because most code assumes that that's not
a thing (and I'd argue that it shouldn't be a thing).

I think that to really decide on this intelligently, we would need a very
detailed analysis of what exactly adding default constructors would change
and how it would interact with existing features. It's one of those things
that seems simple at first glance (especially if you're just thinking about
the case of declaring a stack variable), but the way that init works is
pretty deeply ingrained into D's DNA. And even if we all agreed that we
would ideally have default constructors, with all of the code that already
exists which explicitly uses the init value of a type (including a lot of
templated code) or which assumes that the default value of a type is known
at compile time, adding default constructors into the mix could subtly break
a bunch of stuff.

I could easily see it being the case that we can cleanly add default
constructors to most parts of the language only to find some corner case
where it's a serious problem. Similarly, I could easily see it being the
case that we're able to cleanly deal with all of the language issues and
make it work, but because of all of the existing code that assumes that it's
not a thing, we have some pretty serious problems in practice. It could also
very well be that we could make it work quite well, but I strongly suspect
that at minimum, the general assumption that init is the default value of a
type is going to make it so that adding default constructors will be pretty
problematic in practice even if it would work fine in theory.

So, I don't really want to say that we should do it or that we shouldn't.
And I think that it's a very different question if we're looking at whether
we would do it if were creating D from scratch vs there already being a
bunch of existing D code.

I have no problem with us exploring the idea, but I think that this is a
case where if we want to seriously consider making a change, we need a
_very_ detailed analysis of the situation with it being very clear how the
changes would affect things so that we can weigh the pros and cons with all
of that information - and I suspect that none of us are going to really want
to take the time to do that (and it will likely take someone with a very
detailed understanding of a bunch of the intricate details to be able to do
the analysis correctly).

The simplest solution would likely be to simply make it like structs that
have disabled default initialization in that types with default constructors
won't work in a bunch of situations (potentially making it so that they only
really work when you're just looking to declare one as a stack variable),
but if that's what someone wants, at the moment, they could just disable
default initialization on the type and give it a static opCall, forcing you
to do something like

    auto foo = Foo();

instead of

    Foo foo;

like someone might want to do, but functionally, it's the same. And since
default initialization would be disabled, no one could make the mistake of
doing

    Foo foo;

by accident instead of

    auto foo = Foo();

So, I'm not sure that it's really a good idea to add a language solution
just for that case - but it's also something that's much easier to reason
about than adding default constructors in general.

- Jonathan M Davis





More information about the Digitalmars-d mailing list