October 01

On Tuesday, 1 October 2024 at 06:39:21 UTC, Walter Bright wrote:

>

Manu suggested an intrinsic, something like:

__rvalue(s)

where __rvalue is a keyword.

Nice!

October 01

On Monday, 30 September 2024 at 16:05:16 UTC, Walter Bright wrote:

>

I've been implementing move constructors. They are working, at least on my test cases so far. They are distinguished by a copy constructor takes its argument by ref, and a move constructor by value:

struct S
{
    this(ref S); // copy constructor
    this(S);     // move constructor
}

Is it necessary to breed entities? Doesn't std.algorithm.move do everything we need?

import core.stdc.stdlib : malloc, free;
import core.stdc.string : memcpy;

import std.algorithm.mutation : move;
import std.exception : enforce;
import std.stdio : writeln;

struct S {
    void* content;
    size_t size;

    this(size_t n) {
        writeln("regular ctor");  // debug
        init(n);
    }

    this(ref return scope const S rhs) {
        writeln("copy ctor");  // debug
        init(rhs.size);
        memcpy(this.content, rhs.content, rhs.size);
    }

    private void init(size_t n) {
        this.content = malloc(n);
        enforce(this.content != null, "Memory allocation error.");
        this.size = n;
    }
}

void main() {
    S obj1 = S(1024);
    assert(obj1.content != null);
    S obj2 = move(obj1);  // moving
    assert(obj1.content == null);
    assert(obj2.content != null);

    S obj3 = S(obj2);  // copying
    assert(obj3.content != obj2.content);
    assert(obj3.size == obj2.size);
}

October 02
Now to get annoying again:

What is the difference between move assignment @move + reference counting, and move constructors?

```d
void caller() {
	T thing = ...; // rc: 1
	call1(thing);
	call2(thing);
	// ?reachable thing
	thing.opRCSub(); // elided due to having been moved
	thing.__dtor; // elided due to reachable type state
}

void call1(T thing) {
	thing.opRCAdd(); // elided due to pair
	thing.opRCSub(); // elided due to pair
	thing.__dtor;
}

void call2(@move T thing) {
	thing.opRCAdd(); // elided due to @move
	thing.opRCSub();
	thing.__dtor;
}
```

October 01
On 10/1/2024 12:27 AM, Dukc wrote:
> Why special syntax? `move` is a DRuntime function so it's expected that it can have special semantics, even without special syntax.

Converting to an rvalue is an enabler of other functions, too, not just move. __rvalue is a building block, not a complete function.
October 01
On 10/1/2024 1:59 AM, Richard (Rikki) Andrew Cattermole wrote:
> Why do you need to?

A move constructor just has to initialize the object. A move assignment has to destroy the target first, then move.

They are fundamentally different.
October 01
On 10/1/2024 12:25 AM, Dukc wrote:
> You can make it to work with a compiler instrinsic. The intrinsic would either be an UDA applied to `move` that allows the compiler to make those assumptions, or an intrinsic function that works along the lines of `nove` and `moveEmplace`. The public DRuntime functions would forward or alias to the instrinsic function.

move() is an unhappy maze of templates. We need something a lot simpler.
October 01
On 10/1/24 06:55, Per Nordlöw wrote:
> On Monday, 30 September 2024 at 19:37:04 UTC, Timon Gehr wrote:
>> Otherwise, maybe expose explicit moves. This is useful generally. Can just be `move(x)`, where `move` is either special, or is a function with a "move by default" attribute on its parameter, as we discussed previously.
> 
> Considering the template-complexity of the current implementation of `core.lifetime.move` it will beneficial compile-time wise to make `move` become a builtin. Ideally I would like to have a special syntax for converting an l-value to an r-value.

I think in case we did go the function route, I think any implementation of `move` that is much more complex than the following is a failure:

```d
auto move(T)(@moved T arg)=>arg;
```

Of course, going with a built-in makes sense too.
October 01
On 10/1/24 19:37, Walter Bright wrote:
> On 10/1/2024 12:27 AM, Dukc wrote:
>> Why special syntax? `move` is a DRuntime function so it's expected that it can have special semantics, even without special syntax.
> 
> Converting to an rvalue is an enabler of other functions, too, not just move. __rvalue is a building block, not a complete function.

`move` currently accepts an lvalue and moves it into the return value, leaving `.init` in the argument.

I guess the new implementation you have in mind is something like the following?

```d
auto move(T)(ref T arg)=>__rvalue(arg);
```
October 01
On Tuesday, 1 October 2024 at 17:37:37 UTC, Walter Bright wrote:
> On 10/1/2024 12:27 AM, Dukc wrote:
>> Why special syntax? `move` is a DRuntime function so it's expected that it can have special semantics, even without special syntax.
>
> Converting to an rvalue is an enabler of other functions, too, not just move. __rvalue is a building block, not a complete function.

The __rvalue route makes sense and is intuitive imo.
October 02
On Tuesday, 1 October 2024 at 03:07:02 UTC, Richard (Rikki) Andrew Cattermole wrote:
> On 01/10/2024 3:58 PM, Atila Neves wrote:
>> On Monday, 30 September 2024 at 20:28:05 UTC, Richard (Rikki) Andrew Cattermole wrote:
>>> I suspect that we're going in an entirely wrong direction with move constructors for two reasons:
>>>
>>> 1. Nobody has been able to answer what the purpose of them is, is it an optimization, is it ownership transfer system (which is better done with isolated).
>> 
>> My understanding is that we need SSA in order to implement isolated. And so for now I'd say it's an optimisation mostly, but also bug prevention with move-only types.
>
> SSA? What? That has nothing to do with it.

Not according to Amaury.