| |
| Posted by Jonathan M Davis | PermalinkReply |
|
Jonathan M Davis
| On Wednesday, October 9, 2024 12:54:21 AM MDT Manu via Digitalmars-d wrote:
> On Wed, 9 Oct 2024 at 16:09, Jonathan M Davis via Digitalmars-d <
> > Aside from whatever Walter's reasoning is, there are existing constructors in the wild which use
> >
> > this(S)
> >
> > to construct a copy of a struct. This allows code such as
> >
> > auto s = S(otherS);
> >
> > and
> >
> > auto s = new S(otherS);
> >
> > to compile. This is particularly useful in generic code where you're
> > dealing
> > with a variant type, since without that, you have to either use a static
> > if
> > branch every time that you construct it in case the variant type is being
> > passed in, or you have to create the type with a wrapper function that
> > does
> > the static if for you. By just creating a constructor that specifically
> > takes the same type (or having a templated constructor which does the
> > appropriate static if internally), that issue is avoided. And while it can
> > certainly be argued whether that's the best approach, it's an approach
> > that
> > exists in the wild today. So, if
> >
> > this(S)
> >
> > suddenly becomes a move constructor, existing code will have a normal constructor suddenly turned into a move constructor.
>
> Hmmmm. Well, that's not and never was a copy constructor... so are we required to accept that that was ever correct code?
It's perfectly legal D. There is not and never has been a requirement that you can't have a constructor that takes the same type as the original type. Copy constructors didn't even used to exist in the language at all. You can certainly argue that such a constructor is a bad idea, but it's perfectly legal, and it exists in the wild. And unlike copy constructors or move constructors, it's just a normal constructor.
> It's already problematic enough that copy constructors don't have an
> > explicit identifier of some kind (which IMHO really should be fixed).
>
> What kind of problem is a result of copy constructors not having an identifier?
Rather than giving the ability to indicate that a constructor is a copy constructor, copy constructors are thoroughly restricted such that they can't even be templated (which is a serious problem, particularly when attributes get involved). And in order to get them to even work in many circumstances, you're forced to put a veritable sea of attributes on them (which of course shouldn't be necessary, but that's a separate issue), making it so that figuring out that something is a copy constructor requires examining the signature fairly closely. It would be _far_ cleaner to have them clearly marked so that they would not only be easy to find, but the compiler could tell you when you got it wrong, whereas right now, you have to hope (and test) that you actually declared a copy constructor that gets used as a copy constructor.
On top of that, the current situation is a royal pain with regards to metaprogramming. Finding the constructor which is the copy constructor requires some very careful metaprogramming to ensure that you correctly determine which one it is - or that you correctly determine whether there's even one there at all. And that's because it's not clearly marked as a copy constructor in any way, shape, or form. You have to know what the exact type is your dealing with and examine the parameters appropriately to figure it out, and it's much harder to do than I would have ever expected, and it really should not be that hard. It would be _so_ much cleaner if the copy constructor were treated as distinct rather than just another constructor, particularly since it really isn't just another constructor even if it looks like one.
Of course, the far bigger problem with copy constructors is that the compiler is utter garbage at generating them when a struct has any member variables with copy constructors. It won't ever generate more than one, and it insists on it being inout, whereas the correct solution would be to generate all of the various combinations that are required based on the struct's member variables (both with regards to type qualifers and attributes). The result is that you quickly get into a disgusting mess if you don't declare copy constructors with a very specific signature that won't work in many situations - and with stuff like ranges where you're calling a function that someone else wrote instead of declaring all of the types yourself, you're just screwed, because those realistically need to have the compiler generating the copy constructors for you instead of the programmer declaring them manually (since whether they should even exist depends on the template arguments, as do which overloads should exist).
As things stand, copy constructors in D are borderline garbage. They only work well in very simple circumstances.
- Jonathan M Davis
|