July 12, 2018
On Wed, 11 Jul 2018 at 23:55, RazvanN via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> > What's wrong with:
> > struct S {
> >   this(ref S copyFrom);
> > }
> >
> > That looks like a perfectly good copy constructor declaration ;) I'm just saying, the DIP needs to explain this.
>
> That is actually a valid constructor, according to today's
> compiler. There
> might be code out there that uses this syntax for the constructor
> and overnight
> it will be turned into a copy constructor.

Exactly. Is that a problem?
It probably IS a copy constructor already, what else could it be? :)

> I agree that the current syntax is lacking. This was Andrei's
> proposition
> and I was initially against it, but he said to put it in the DIP
> so that
> we can discuss it as a community. Maybe this syntax is better:
>
> @this(ref S a another)
>
> It looks like the c++ copy constructor but the `@` makes it
> different from
> a constructor, so we're good. What do you think?

I would struggle to get behind anything other than `this(ref T)`
1. There's an extremely low probability such a function exists in any
code, because it's redundant in the current language (postblit)
2. If it does exist, there's an extremely low probability that it's
not already a valid copy constructor (what else could it possibly
be?!)
3. The remaining cases are crazy.

extremely^^2 low probability of causing an issue is not worth
butchering the syntax for all time to come... if you ask me.
Can the DIP identify a couple of trouble cases and present as
motivation for the silly syntax? If no such cases can be identified,
then it's hard to support an argument in favour.

> > Right. This is all obvious and intuitive.
> > What I'm hearing is that under this proposal, copy constructors
> > and
> > assignment operators DO come in pairs (just like in C++), but
> > that's
> > not mentioned here in this DIP. Since this proposal will
> > introduce
> > that recommended pattern from C++, it may be worth mentioning.
>
> If by "come in pairs" you mean that you can define them both,
> then yes,
> that is the case. Will add a paragraph in the DIP to specify this.

Well, in C++ they SHOULD come in pairs. Things don't work if they
don't, and I expect the same truth will emerge here.
I'd like to see the DIP explore the parallel; understand why C++
specifies that they must come in pairs, and then explain that the same
reasons also apply to D, or why they don't.
Does dlang now have the 'rule-of-3' (or 5 now in c++11)?

> You mentioned that it's terrible that the assignment operator
> and the copy constructor come in pairs. Why is that? Would you
> rather
> have a copy constructor that is used also as an assignment
> operator?

It's pretty lame that C++ requires you to effectively write the same
function twice in 2 different ways. It might be nice to explore if
there's any way to unify them...
I often define C++ assignment operators like this to save on code duplication:
  T& operator=(const T& rh) { this->~T(); new(this) T(rh); }

I would hate to see this emerge as a pattern:
  void opAssign(ref T rh) { this.destroy(); emplace(&this, rh); }

Being able to implement them both independently is *occasionally* useful, but 95% of the time, destruct + copy-construct is an equally efficient implementation for assignment. I'd suggest that this destruct+copy-construct pattern is a perfectly good substitute for assignment in most cases, and maybe the compiler should deploy the pattern as an implicit copy constructor in lieu of an explicit one? So, if the user specifies a complex copy constructor, but no assignment operator (which just blits on copy), then they've almost certainly introduced a bug on copying! Perhaps the compiler should automatically emit an assignment operator implemented as above in presence of a (suite of? [const/immutable/etc permutations]) 'complex' copy constructor?
July 12, 2018
On Thu, 12 Jul 2018 at 06:45, Andrei Alexandrescu via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 07/10/2018 06:50 PM, Manu wrote:
> > On Tue, 10 Jul 2018 at 15:23, Jonathan M Davis via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> >>
> >> On Tuesday, 10 July 2018 14:58:09 MDT Manu via Digitalmars-d wrote:
> >>> 2. It looks like copy constructors are used to perform assignments
> >>> (and not constructions)... but, there is also opAssign. What gives?
> >>>      Eg:
> >>>        S b = a; // <- copy construction? looks like an assignment.
> >>>      And not:
> >>>        S b = S(a); // <- actually looks like a construction, but this
> >>> syntax seems to not be intended (and rightly so, it's pretty terrible)
> >>
> >> S b = a;
> >>
> >> has never been assignment in either C++ or D. It's initialization / construction, which means that it calls a constructor - be that a postblit constructor or a copy constructor. Assignment only occurs when you're giving an existing object a new value.
> >
> > I know this, but it's not syntactically obvious, it just depends on the fact that you already know that fact... I feel a DIP about copy construction needs to have some text explaining that, and where the edges are.
>
> The DIP is not a tutorial on existing related parts of the language. Copy initialization has been distinct from assignment for a long time in both C++ and D languages.

Okay. Well, I guess that I just wanted some clarity on exactly what 'initialisation' looks like.

T b = a; // clearly initialisation, sure
T c = T(a); // c is initialised to a copy of an rvalue which was
initialised as a copy of a. Is there *two* calls to the copy
constructor here?

In this way, is an explicit call to the copy constructor is allowed? You said it is, but the word "@implicit" makes it look like explicit calls should be an arbitrary error; change the word at least.

C++ is a disaster zone these days with `T t = x;`  `T t = T(x);`  `T
t(x);`  `T t{x};`... I just wanna make sure we don't end up with
initialisation 'cases'.

> > Is an initialisation assignment can use a copy constructor, why can't a normal assignment implicitly use a copy constructor? (implicit destruct then copy-construct)
>
> Because assignment and construction were, and are, distinct operation. There is no need for the DIP to explain.

Right, but as I've alluded to before, there's a loose relationship
here. C++ prescribes the 'rule of 3' (or 5). If we introduce copy
constructors, are we introducing those concepts?
I think introduction of those concepts may pull questions about
assignment into the definition space.

> >> And why would
> >>
> >> S b = S(a);
> >>
> >> not be intended? Sure, it's kind of pointless if a is an S, but if you have a copy constructor, it makes perfect sense that S(a) would work and would be pretty bizarre if it didn't, since it's explicitly calling the copy constructor.
> >
> > But there's a super explicit `@implicit` thing written right there... so should we expect that an *explicit* call to the copy constructor is not allowed? Or maybe it is allowed and `@implicit` is a lie?
>
> The "@implicit" attribute does not preclude explicit calls. Razvan: you may want to mention that.

Okay. In that case, I really don't like the name.
July 12, 2018
On Thu, 12 Jul 2018 at 06:50, Andrei Alexandrescu via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 07/11/2018 11:11 AM, Atila Neves wrote:
> > On Wednesday, 11 July 2018 at 07:40:32 UTC, RazvanN wrote:
> >>> But there's a super explicit `@implicit` thing written right there... so should we expect that an *explicit* call to the copy constructor is not allowed? Or maybe it is allowed and `@implicit` is a lie?
> >>
> >> The @implicit is there to point out that you cannot call that method
> >> explicitly; it gets called for you implicitly when you construct an
> >> object
> >> as a copy of another object.
> >
> > How is this different from other types of constructors or destructors?
>
> The main difference is that the compiler may insert calls to it implicitly.

You mean like ~this(), and op[Anything](), and front() and popFront()
and empty()?
I don't think we need this attribute.
July 12, 2018
On Thu, 12 Jul 2018 at 07:15, Andrei Alexandrescu via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 07/12/2018 09:49 AM, Atila Neves wrote:
> > On Thursday, 12 July 2018 at 06:54:37 UTC, RazvanN wrote:
> >
> >> [...]
> >
> >> If by "come in pairs" you mean that you can define them both, then yes, that is the case. Will add a paragraph in the DIP to specify this.
> >>
> >> You mentioned that it's terrible that the assignment operator
> >> and the copy constructor come in pairs. Why is that? Would you rather
> >> have a copy constructor that is used also as an assignment operator?
> >
> > Because, like in C++, now you have to implement both and make sure they do the same thing. Boilerplaty and a recipe for disaster.
> >
> > Atila
>
> There's no meaningful way to avoid that. The two operations are fundamentally different, are typechecked differently, and actually are different in the presence of qualifiers on fields.
>
> Introspection is a key helper here compared to C++.

As I've said elsewhere, opAssign() can be fabricated by:
  this.destroy(); emplace(&this, copyFrom);

We should consider fabricating an implicit assignment operator in the
presence of an elaborate copy constructor.
As you say, this interacts with qualifiers... I don't think it's
trivial, but I think it should be explored. Otherwise whenever anyone
forgets to implement an assignment operator, it'll just blit, which is
almost certainly incorrect.
July 12, 2018
On Thu, 12 Jul 2018 at 06:50, Andrei Alexandrescu via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 07/11/2018 11:11 AM, Atila Neves wrote:
> > On Wednesday, 11 July 2018 at 07:40:32 UTC, RazvanN wrote:
> >>> But there's a super explicit `@implicit` thing written right there... so should we expect that an *explicit* call to the copy constructor is not allowed? Or maybe it is allowed and `@implicit` is a lie?
> >>
> >> The @implicit is there to point out that you cannot call that method
> >> explicitly; it gets called for you implicitly when you construct an
> >> object
> >> as a copy of another object.
> >
> > How is this different from other types of constructors or destructors?
>
> The main difference is that the compiler may insert calls to it implicitly.
>
> > I also very much dislike the syntax - it makes no sense to me at all. I commented on the PR itself asking why it differs so much from C++ - specifically, what's bad about the C++ way of doing things there that we want to avoid?
>
> C++ is at the other end of the spectrum - constructors are too implicit, so the "explicit" keyword has been introduced with the advice to use it in the vast majority of cases. If C++ could do it again, it would make everything explicit and add an "implicit" keyword.

Ohhh yeah, this. I finally understand your reasoning here!
Okay, that is a meaningful use for @implicit, and I could get behind
its introduction if it were extended to apply broadly to any
constructor. If it's only used in this isolated case, and specifically
disallowed in that useful broader case, it feels pointless, and
probably a cause of frustration for people that expect that it should
work broadly.

The DIP mentions that it may be deployed broadly, but I'd like to see that resolved up-front. I could only decide to accept it in this case depending on that secondary decision.
July 12, 2018
On Tue, 10 Jul 2018 at 03:50, RazvanN via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> Hi everyone!
>
> I managed to put together a first draft of the DIP for adding the copy constructor to the language [1]. If anyone is interested, please take a look. Suggestions and comments about technical aspects and wording are all welcome.
>
> Thanks,
> RazvanN
>
> [1] https://github.com/dlang/DIPs/pull/129

I'd like to see a mention on extern(C++) copy constructors; are they
naturally semantically compatible? If not, how will it behave
differently when extern(C++) is applied (ie, like C++)?
Normal constructors and destructors change semantics in the presence
of extern(C++).
July 12, 2018
On Thu, 12 Jul 2018 at 08:30, Luís Marques via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Thursday, 12 July 2018 at 15:14:19 UTC, Luís Marques wrote:
> > More details. The DIP says:
> >
> > "The structName type needs to be identical to typeof(this); an
> > error is issued otherwise. This requirement may be relaxed in
> > the future in order to accomodate copying from objects of a
> > different type"
> > (BTW, typo in "accomodate")
> >
> > That would mean that if such a relaxation were introduced, then suddenly *all* copy ctors would imply implicit conversion between the respective types. Given D's stance on implicit conversions, I suspect that's not going to pass mustard. So I would prefer the any "implicit" keyword-like annotation to be reserved for explicitly approved implicit conversions.
>
> BTW: Multiple alias this is still planned for inclusion in D, right? If so, what would be the (pratical?) difference between having copy ctors with such a relaxed type requirement and just defining an equivalent alias this method? In case the answer is that there's no significant difference, why not drop multiple alias this, then?

@implicit constructors state what types an object may *accept*. alias this specifies what types an object may *provide*.

They're both about implicit conversion, but specified at either the providing or receiving end. I think they both have reason to exist; they're complementary. It depends if you're authoring an API, or writing a tool to interact with an existing API which is appropriate to use.

July 12, 2018
On Thu, 12 Jul 2018 at 08:36, Andrei Alexandrescu via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On 07/12/2018 11:14 AM, Luís Marques wrote:
> > On Thursday, 12 July 2018 at 14:56:33 UTC, Luís Marques wrote:
> >> When designing D libraries than lean towards DSL style, I've frequently felt impaired by the lack of implicit conversions in D. In my experience, it's not that all types need to be implicitly convertible to other types. Just being able to mark a few types as implicitly convertible to some other specific types would go a long way to alleviate the limitations I felt. It would also solve problems like an arbitrary limit on the depth of implicit conversions.
> >>
> >> I had imagined that maybe one day an implicit keyword could be introduced to mark such permissible implicit conversions. Seeing an implicit "keyword" being introduced here with different semantics than I envisioned makes me even less hopeful that some day such implicit conversions annotations could be introduced. So... maybe consider choosing some other syntactic notation? Besides, the fact that the compiler can implicitly introduce calls to the copy ctor doesn't strike me as something particularly central to the concept, so it seems like an odd choice for something to distinguish a copy ctor.
> >
> > More details. The DIP says:
> >
> > "The structName type needs to be identical to typeof(this); an error is
> > issued otherwise. This requirement may be relaxed in the future in order
> > to accomodate copying from objects of a different type"
> > (BTW, typo in "accomodate")
> >
> > That would mean that if such a relaxation were introduced, then suddenly *all* copy ctors would imply implicit conversion between the respective types.
>
> No, only constructors annotated with @implicit would be implicit. But that's only a possible future direction not part of this DIP.
>
> Also there are many complications related to allowing implicit conversions across distinct types, and this DIP should not get embroiled in those. That would be a different pursuit that I encourage you to consider.

I feel like this DIP depends on an @implicit DIP, and that one needs to come first...

July 12, 2018
On 7/12/18 2:30 PM, ag0aep6g wrote:
> On 07/12/2018 03:40 PM, Andrei Alexandrescu wrote:
>> On 07/10/2018 04:58 PM, Manu wrote:
> [...]
>>> 1. Explain the need and reasoning behind `@implicit`.
>>
>> Razvan: I think it would help to explain that the attribute is necessary to avoid changing semantics of existing code. Thanks.
> 
> You're still potentially changing the semantics of existing code. `@implicit` can be a UDA today:
> 
> ----
> enum implicit = 0;
> struct C
> {
>      @implicit this(ref C another) {}
> }
> ----
> 
> Today, that's a normal constructor. With the DIP, it becomes a copy constructor.

That is correct and a liability of the current DIP. That should be mentioned in it.
July 12, 2018
On 7/12/18 4:29 PM, Manu wrote:
> Being able to implement them both independently is*occasionally*
> useful, but 95% of the time, destruct + copy-construct is an equally
> efficient implementation for assignment. I'd suggest that this
> destruct+copy-construct pattern is a perfectly good substitute for
> assignment in most cases, and maybe the compiler should deploy the
> pattern as an implicit copy constructor in lieu of an explicit one?
> So, if the user specifies a complex copy constructor, but no
> assignment operator (which just blits on copy), then they've almost
> certainly introduced a bug on copying! Perhaps the compiler should
> automatically emit an assignment operator implemented as above in
> presence of a (suite of? [const/immutable/etc permutations]) 'complex'
> copy constructor?

Not the charter of the current DIP.