Thread overview
How do I use `__rvalue` expression on a struct property?
Apr 27
Manu
Apr 29
Manu
Apr 27
Manu
April 24

I'm exploring the new __rvalue expressions, and got stuck while creating a move constructor for a container(non-copyable) with a non-copyable container property.

import core.stdc.stdio : printf;
import core.memory : pureMalloc, pureFree;
struct S {
    @("mallocd") ubyte[] p;
    this() @disable;
    this(this) @disable;
    this(ubyte[] p) @nogc @trusted nothrow {
        printf("Base constructor!\n");
        this.p = p;
    }

    this(S rhs) @nogc @trusted nothrow {
        printf("Move constructor!\n");
        p = rhs.p;
        rhs.p = null;
    }

    ~this() pure @nogc @trusted nothrow {
        if (p) {
            pureFree(p.ptr);
            p = null;
        }
    }
}

struct Container {
    S s;
    this() @disable;
    this(this) @disable;
    this(S s) @nogc @trusted nothrow {
        this.s = __rvalue(s);
    }

    this(Container rhs) @nogc @trusted nothrow {
        this.s = __rvalue(rhs.s);
    }
}

Above code results in compilation error:

<source>(35): Error: struct `example.S` is not copyable because it has a disabled postblit
        this.s = __rvalue(rhs.s);

I've looked into the language reference but could not find a way to move a property of a rvalue object instance.

April 24
On 4/24/25 10:23, Jiten Devlani wrote:
> I'm exploring the new `__rvalue` expressions, and got stuck while creating a move constructor for a container(non-copyable) with a non- copyable container property.
> 
> ```d
> import core.stdc.stdio : printf;
> import core.memory : pureMalloc, pureFree;
> struct S {
>      @("mallocd") ubyte[] p;
>      this() @disable;
>      this(this) @disable;
>      this(ubyte[] p) @nogc @trusted nothrow {
>          printf("Base constructor!\n");
>          this.p = p;
>      }
> 
>      this(S rhs) @nogc @trusted nothrow {
>          printf("Move constructor!\n");
>          p = rhs.p;
>          rhs.p = null;
>      }
> 
>      ~this() pure @nogc @trusted nothrow {
>          if (p) {
>              pureFree(p.ptr);
>              p = null;
>          }
>      }
> }
> 
> struct Container {
>      S s;
>      this() @disable;
>      this(this) @disable;
>      this(S s) @nogc @trusted nothrow {
>          this.s = __rvalue(s);
>      }
> 
>      this(Container rhs) @nogc @trusted nothrow {
>          this.s = __rvalue(rhs.s);
>      }
> }
> ```
> 
> Above code results in compilation error:
> ```
> <source>(35): Error: struct `example.S` is not copyable because it has a disabled postblit
>          this.s = __rvalue(rhs.s);
> ```
> 
> I've looked into the language reference but could not find a way to move a property of a rvalue object instance.

Seems this is a bug, you can report it here:
https://github.com/dlang/dmd/issues/new

This workaround appears to work:

```d
    this(Container rhs) @nogc @trusted nothrow {
	    scope tmp=&rhs.s;
	    this.s = __rvalue(*tmp);
    }
```
April 27
On Sunday, 27 April 2025 at 02:41:53 UTC, Walter Bright wrote:
> Postblits and rvalue references do not mix.
>
> Move constructors and rvalue references are a replacement for postblits. We didn't make any effort to reconcile the two.
>
> If you're going to use move constructors and rvalue references, just delete the postblit code from the struct hierarchy.
>
> Postblits are now an obsolete feature, left for legacy code.

Unfortunately, until druntime is updated to fully support copy constructors, it will be necessary to continue using postblits in new code.
April 27
Yes, but like I've said to you before, they're problematic and find
themselves interfering with the situation frequently.
It's possible to reconcile this, but I agree it would be better to move
away... but that's very hard to do in practise.
postblit has innertia, and failure to implement copy/move constructors
because of an interaction with postblit tends to lead to resolving the
issue by writing another postblit... that doesn't lead us in the right
direction.

On Sun, 27 Apr 2025 at 11:46, Walter Bright via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> Postblits and rvalue references do not mix.
>
> Move constructors and rvalue references are a replacement for postblits.
> We
> didn't make any effort to reconcile the two.
>
> If you're going to use move constructors and rvalue references, just
> delete the
> postblit code from the struct hierarchy.
>
> Postblits are now an obsolete feature, left for legacy code.
>


April 27
FWIW; user code shouldn't contain __rvalue directly.
You can define a move function like:
   ref T move(T)(ref T value) __rvalue => value;

Then you can do:
  T x = var.move;  // move construction

`forward` can be implemented similarly.

On Thu, 24 Apr 2025 at 18:26, Jiten Devlani via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> I'm exploring the new `__rvalue` expressions, and got stuck while creating a move constructor for a container(non-copyable) with a non-copyable container property.
>
> ```d
> import core.stdc.stdio : printf;
> import core.memory : pureMalloc, pureFree;
> struct S {
>      @("mallocd") ubyte[] p;
>      this() @disable;
>      this(this) @disable;
>      this(ubyte[] p) @nogc @trusted nothrow {
>          printf("Base constructor!\n");
>          this.p = p;
>      }
>
>      this(S rhs) @nogc @trusted nothrow {
>          printf("Move constructor!\n");
>          p = rhs.p;
>          rhs.p = null;
>      }
>
>      ~this() pure @nogc @trusted nothrow {
>          if (p) {
>              pureFree(p.ptr);
>              p = null;
>          }
>      }
> }
>
> struct Container {
>      S s;
>      this() @disable;
>      this(this) @disable;
>      this(S s) @nogc @trusted nothrow {
>          this.s = __rvalue(s);
>      }
>
>      this(Container rhs) @nogc @trusted nothrow {
>          this.s = __rvalue(rhs.s);
>      }
> }
> ```
>
> Above code results in compilation error:
> ```
> <source>(35): Error: struct `example.S` is not copyable because
> it has a disabled postblit
>          this.s = __rvalue(rhs.s);
> ```
>
> I've looked into the language reference but could not find a way to move a property of a rvalue object instance.
>


April 26
Postblits and rvalue references do not mix.

Move constructors and rvalue references are a replacement for postblits. We didn't make any effort to reconcile the two.

If you're going to use move constructors and rvalue references, just delete the postblit code from the struct hierarchy.

Postblits are now an obsolete feature, left for legacy code.
April 27
On 4/27/25 04:41, Walter Bright wrote:
> Postblits and rvalue references do not mix.
> 
> Move constructors and rvalue references are a replacement for postblits. 

Postblits are for copies, not moves. The point of the `@disable this(this)` in OT's code is to disable copying. I guess instead the copy constructor should be disabled, but I still think it should not attempt to call a postblit on move.
April 27
On 4/27/25 04:01, Manu wrote:
> Yes, but like I've said to you before, they're problematic and find themselves interfering with the situation frequently.
> It's possible to reconcile this, but I agree it would be better to move away... but that's very hard to do in practise.
> postblit has innertia, and failure to implement copy/move constructors because of an interaction with postblit tends to lead to resolving the issue by writing another postblit... that doesn't lead us in the right direction.

I think ideally this would be resolved by simply generating a copy constructor that calls the postblit if there is a postblit and generating a disabled copy constructor if the postblit is disabled. Then, can just delete all existing postblit-related logic from the compiler source.

Of course, one issue here is that postblit is not type safe/memory safe. So in the long run, would be better to get rid of them or restrict them to work only for mutable copies unless they are `pure`.

I tend to find postblit convenient enough in the cases where it is sufficiently expressive, so I would be somewhat sad to see them go completely, but I understand some of the arguments in favor of that.
April 27
On 4/27/25 19:20, Timon Gehr wrote:
> or restrict them to work only for mutable copies unless they are `pure`.

(More restrictions would be needed to enable qualified copying, due to aliasing issues.)
April 29
On Mon, 28 Apr 2025 at 03:26, Timon Gehr via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On 4/27/25 04:01, Manu wrote:
> > Yes, but like I've said to you before, they're problematic and find
> > themselves interfering with the situation frequently.
> > It's possible to reconcile this, but I agree it would be better to move
> > away... but that's very hard to do in practise.
> > postblit has innertia, and failure to implement copy/move constructors
> > because of an interaction with postblit tends to lead to resolving the
> > issue by writing another postblit... that doesn't lead us in the right
> > direction.
>
> I think ideally this would be resolved by simply generating a copy constructor that calls the postblit if there is a postblit and generating a disabled copy constructor if the postblit is disabled. Then, can just delete all existing postblit-related logic from the compiler source.
>
> Of course, one issue here is that postblit is not type safe/memory safe. So in the long run, would be better to get rid of them or restrict them to work only for mutable copies unless they are `pure`.
>
> I tend to find postblit convenient enough in the cases where it is sufficiently expressive, so I would be somewhat sad to see them go completely, but I understand some of the arguments in favor of that.
>

Yes exactly... all these things you say.
We will need default (element-wise) copy/move constructors, and they need
to call through to postblits for members with postblits, and that should
position us in a place where we don't continue to proliferate postblits,
and we can eventually deprecate.