October 07
On Sunday, 6 October 2024 at 04:04:28 UTC, Walter Bright wrote:
> ```
> struct S { ... }
>
> this(ref S) // copy constructor
[...]
The above seems to invite `this(mov S)` move constructor.

October 07
On Sunday, 6 October 2024 at 04:04:28 UTC, Walter Bright wrote:
> ```
> struct S { ... }
>
> [...]

Within the language today what part of a move operation actually requires a new form of constructor? Isn't the whole point that you're just transferring ownership of a constructed object?
October 07
On Sunday, 6 October 2024 at 04:04:28 UTC, Walter Bright wrote:
> It may take a bit of getting used to. I kinda prefer (1) as it is sorta like `~this()`.

Maybe silly idea, but could we name it moveThis() and copyThis() ??
October 07
On Monday, 7 October 2024 at 17:29:20 UTC, Dejan Lekic wrote:
> On Sunday, 6 October 2024 at 04:04:28 UTC, Walter Bright wrote:
>> It may take a bit of getting used to. I kinda prefer (1) as it is sorta like `~this()`.
>
> Maybe silly idea, but could we name it moveThis() and copyThis() ??

How about reusing one of those shift operators keyword.

this<<<(T other)
October 07
On Mon, Oct 07, 2024 at 05:42:53PM +0000, Guillaume Piolat via Digitalmars-d wrote:
> On Monday, 7 October 2024 at 17:29:20 UTC, Dejan Lekic wrote:
> > On Sunday, 6 October 2024 at 04:04:28 UTC, Walter Bright wrote:
> > > It may take a bit of getting used to. I kinda prefer (1) as it is
> > > sorta like `~this()`.
> > 
> > Maybe silly idea, but could we name it moveThis() and copyThis() ??
> 
> How about reusing one of those shift operators keyword.
> 
> this<<<(T other)

What about:

	this(~T t)

The ~ being an allusion to ~this, the idea being that after the move the operand t will effectively have been destructed and invalid.


T

-- 
Why waste time reinventing the wheel, when you could be reinventing the engine? -- Damian Conway
October 07
On Monday, 7 October 2024 at 18:04:58 UTC, H. S. Teoh wrote:
>
> What about:
>
> 	this(~T t)
>
> The ~ being an allusion to ~this, the idea being that after the move the operand t will effectively have been destructed and invalid.
>
>
> T

I love it! intuitive (unlike most of the other suggestions).

October 07
On Sunday, October 6, 2024 10:43:34 AM MDT Paul Backus via Digitalmars-d wrote:
> On Sunday, 6 October 2024 at 04:04:28 UTC, Walter Bright wrote:
> > As the above illustrates, a move constructor cannot be distinguished from a regular constructor by syntax alone. It needs semantic analysis.
>
> It's worth pointing out that this is not just a problem for move constructors; it's also a problem for copy constructors. Specifically, it's what prevents copy constructors from being templates.
>
> As a result, if you're writing generic code and want to handle arbitrary combinations of type qualifiers on the original object and the copy, you cannot do the simple, obvious thing and use a template, like this:
>
>      this(this This, Other)(ref Other other)
>      if (is(immutable Other == immutable typeof(this))
>      {
>          // copy logic
>      }
>
> Instead, you must write individual copy constructor overloads for every combination of qualifiers:
>
>      // Function bodies omitted for brevity
>      // mutable original
>      this(ref typeof(this));
>      this(ref typeof(this)) const;
>      this(ref typeof(this)) immutable;
>      this(ref typeof(this)) inout;
>
>      // const original
>      this(ref const typeof(this));
>      this(ref const typeof(this)) const;
>      this(ref const typeof(this)) immutable;
>      this(ref const typeof(this)) inout;
>
>      // immutable original
>      this(ref immutable typeof(this));
>      this(ref immutable typeof(this)) const;
>      this(ref immutable typeof(this)) immutable;
>      this(ref immutable typeof(this)) inout;
>
>      // inout original
>      this(ref inout typeof(this));
>      this(ref inout typeof(this)) const;
>      this(ref inout typeof(this)) immutable;
>      this(ref inout typeof(this)) inout;
>
>      // etc.
>
> So, whatever solution we come up with for helping the compiler identify move constructors, I hope we can apply it to copy constructors too.

My experience thus far has been that I've been forced to use inout (potentially then casting away const to then do anything useful) and that having more than one copy constructor falls flat on its face once you put your type with a copy constructor inside any other type, because the compiler fails to generate all of the necessary copy constructors and just complains that inout doesn't work.

There are similar problems with the various function attributes which aren't type qualifiers.

Razvan create a PR to try to improve that situation, but it hasn't gone anywhere:

https://github.com/dlang/dmd/pull/16429

Really, it would be nice to be able to just templatize the copy constructor and have all of the corresponding copy constructors generated properly in any other types that have that type as member. The current state of things strongly implies that copy constructors were implemented and tested only in fairly simple situations. They're just too much of a mess in practice.

- Jonathan M Davis



October 07
On Monday, October 7, 2024 10:21:50 AM MDT max haughton via Digitalmars-d wrote:
> On Sunday, 6 October 2024 at 04:04:28 UTC, Walter Bright wrote:
> > ```
> > struct S { ... }
> >
> > [...]
>
> Within the language today what part of a move operation actually requires a new form of constructor? Isn't the whole point that you're just transferring ownership of a constructed object?

IIRC, the whole reason that we originally got a DIP for a move version of a postblit (which then became a DIP for move constructors once we determined that postblits didn't make sense due to issues with type qualifiers) is because Weka has a use case where they store pointers to structs on the stack in some sort of table somewhere (with other fibers accessing it on some basis IIRC). So, if the struct ever moves, their code breaks - and as things stand, the compiler is allowed to assume that moving a struct isn't a problem (whereas in C++, a move constructor is required for the compiler to move a user-defined object).

The result is that Weka has had to be _very_ careful about stuff like RVO to ensure that these particular structs don't get moved, and they care a great deal about which situations result in the compiler decided to move a struct (which, fortunately for them, isn't many at this point), but if they have move constructors, then they can hook the move and tell the table that the address of the struct has changed, and they no longer risks bugs from stray moves.

Personally, I've also run into one case where it made sense to pass a pointer to a struct on the stack to another thread, and being able to disable the ability to move that object would be quite nice even if it's not actually required (and it wouldn't fix the situation where the struct gets destroyed before the pointer is gone).

Now, obviously, for the vast majority of programs, move constructors are completely unnecessary, and because we made it so that the compiler is allowed to move objects by default, we only need move constructors in cases where moving has to be hooked into or disallowed instead of in all cases where it would be needed at all, but we _do_ need move constructors for any situations where someone needs to know that a move has taken place or needs to entirely disallow the ability to move a particular struct.

- Jonathan M Davis



October 08

On Monday, 7 October 2024 at 18:04:58 UTC, H. S. Teoh wrote:

>

What about:

this(~T t)

The ~ being an allusion to ~this, the idea being that after the move the operand t will effectively have been destructed and invalid.

Before you decide that, consider how often we use the ~ symbol. But isn't this (option 2) more meaningful?

this(=MyStruct name) { ... }

The ~ Symbol in D

  • String/Array concatenation
  • Bitwise complement
  • Dynamic expanding array
  • Destructuring functions
  • Exclusive operator with opOpAssign

SDB@79

October 07
On Tue, Oct 08, 2024 at 12:31:44AM +0000, Salih Dincer via Digitalmars-d wrote:
> On Monday, 7 October 2024 at 18:04:58 UTC, H. S. Teoh wrote:
> > 
> > What about:
> > 
> > 	this(~T t)
> > 
> > The ~ being an allusion to ~this, the idea being that after the move the operand t will effectively have been destructed and invalid.
> 
> Before you decide that, consider how often we use the ~ symbol. But isn't this (option 2) more meaningful?
> 
> **this**(**=MyStruct** name) { ... }

Using = in this case is an exceptionally ugly visual clash with default parameters.  Imagine monstrosities like:

	this(=T t=T(1));

Ick.

This looks better:

	this(~T t=T(1));


> **The ~ Symbol in D**
> 
> * String/Array concatenation
> * Bitwise complement
> * Dynamic expanding array
> * Destructuring functions
> * Exclusive operator with opOpAssign
[...]

Since the move ctor name is `this`, the use of `~` immediately reminds one of the dtor `~this`.  One doesn't normally associate ctors with array concatenation or bitwise complement, so the use of `~` would seem to be the more intuitive meaning in the move ctor, which would be spelled `this(~T t)`.


T

-- 
Did you hear about the monkeys who shared an Amazon account?  They were Prime mates!