October 04

On Thursday, 3 October 2024 at 14:27:37 UTC, Imperatorn wrote:

>

On Wednesday, 2 October 2024 at 18:57:24 UTC, Timon Gehr wrote:

>

On 10/2/24 20:00, Walter Bright wrote:

>

[...]

I don't think it affects how overloading works. You just treat it as a by-value argument as far as overloading and lifetime handling is concerned. In terms of ABI however, you pass the argument by reference.

[...]

What is the amount we need to pay to not get another attribute?

This probably wouldn't be a language attribute like @nogc or @trusted. It would be a simple UDA that is defined as a compiler intrinsic. It would likely be defined either at core.attribute, or somewhere at core.internal.

And in any case it wouldn't be anything the D programmer has to deal with. It'd be used to define DRuntime functions, and maybe some low-level Phobos / utility library functions. But not at application code, nor even at normal library code.

October 11
On Monday, September 30, 2024 10:05:16 AM MDT Walter Bright via Digitalmars-d 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
> }
> ```
> So far, so good. Consider:
> ```
> void phone(S s)
> {
>      S t = s;  // copy constructor
> }
> ```
> But what if we want to initialize `t` via a move constructor? Somehow, `s`
> has to be converted from an lvalue to an rvalue. This is done via the
> function rvalue(): ```

Given the we're now looking at having a separate syntax for move constructors, I would argue that they should just have to be ref, which should eliminate the special cases that you're fighting here. Even if an rvalue is being passed in, it has to be _somewhere_ as a temporary, and fundamentally, a move constructor needs an lvalue, since it's moving an object from one location to another, even if the source location is a temporary one.

- Jonathan M Davis



October 12
On Sat, 12 Oct 2024 at 04:20, Jonathan M Davis via Digitalmars-d < digitalmars-d@puremagic.com> wrote:

> On Monday, September 30, 2024 10:05:16 AM MDT Walter Bright via
> Digitalmars-d
> 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
> > }
> > ```
> > So far, so good. Consider:
> > ```
> > void phone(S s)
> > {
> >      S t = s;  // copy constructor
> > }
> > ```
> > But what if we want to initialize `t` via a move constructor? Somehow,
> `s`
> > has to be converted from an lvalue to an rvalue. This is done via the
> > function rvalue(): ```
>
> Given the we're now looking at having a separate syntax for move constructors, I would argue that they should just have to be ref, which should eliminate the special cases that you're fighting here.


You really need to re-read the DIP here and understand the design principle
of this whole thing.
This suggestion show us that you either don't understand the DIP, totally
missed the point, or possibly that you fundamentally disagree with the DIP;
and if that's the case, I think you need to present that argument and what
you'd propose instead, rather than talk with respect to implementation of
the DIP with a completely different idea in mind. If you change the
fundamental substance of the DIP, it's a new DIP.

The proposal in the DIP is very simple; struct rvalues are ref too now, so don't worry about the ref stuff; everything's a ref. The problem to be solved is, how do we appropriately distinguish an rvalue from an lvalue; and while we've had a myriad of proposals adding attributes, Walter found an arrangement where the distinction can be expressed in existing language in an astonishingly elegant way; recognise that by-value calls (accepts rvalue) are all actually move opportunities.

void f(ref T) // arg is an lvalue; the syntax says "I have received a
reference to *someone else's* thing"; or put another way, the callee does
NOT own the argument.
void f(T) // arg is an rvalue; this syntax says "I have received this
thing"; the callee owns the argument, and as such, is a valid recipient of
any move operation.
In order to make move operations actually move operations, they need to be
passed by ref (by *rvalue-ref*, so to speak), and that is literally the
entire point of the DIP; the calling convention is adjusted so a by-value
(r-value) parameter is passed by rvalue-ref.

This is what I mean where I say we're talking about "move semantics", but everyone seems to be fixated on move constructors as if they're an extraordinarily interesting part of this story.

A move constructor is just an efficient initialisation opportunity, and it's a small part of the overall story regarding move semantics.

As I see it; the move constructor *must *be an overload; otherwise, surely
you must assume the overload selection rules don't work, and so every
single other function (aside from the move constructor which received a
blessed hack!) will not make a proper selection.
Move semantics ARE proper overload selection, that's the entire meat of
this design. This design *IS* overload selection rules.... to try and work
that problem off to the side would be to have completely missed the point.
If you exclude overload resolution from the picture, then I don't even know
what we're talking about here.


October 12
On 12/10/2024 6:56 PM, Manu wrote:
> You really need to re-read the DIP here and understand the design principle of this whole thing. This suggestion show us that you either don't understand the DIP, totally missed the point, or possibly that you fundamentally disagree with the DIP; and if that's the case, I think you need to present that argument and what you'd propose instead, rather than talk with respect to implementation of the DIP with a completely different idea in mind. If you change the fundamental substance of the DIP, it's a new DIP.

It may be time for us to get you into a meeting.

Yesterday in the monthly meeting it was determined that Martin and you should talk about moving.

He and I have some similar ideas regarding things like postblit and their interaction with it. So I am confident in a good outcome if he is leading it.

I'll message Mike to reaffirm what I've said here and see if he can't arrange something between everyone.

October 12
On 12/10/2024 7:42 PM, Richard (Rikki) Andrew Cattermole wrote:
> On 12/10/2024 6:56 PM, Manu wrote:
>> You really need to re-read the DIP here and understand the design principle of this whole thing. This suggestion show us that you either don't understand the DIP, totally missed the point, or possibly that you fundamentally disagree with the DIP; and if that's the case, I think you need to present that argument and what you'd propose instead, rather than talk with respect to implementation of the DIP with a completely different idea in mind. If you change the fundamental substance of the DIP, it's a new DIP.
> 
> It may be time for us to get you into a meeting.
> 
> Yesterday in the monthly meeting it was determined that Martin and you should talk about moving.
> 
> He and I have some similar ideas regarding things like postblit and their interaction with it. So I am confident in a good outcome if he is leading it.
> 
> I'll message Mike to reaffirm what I've said here and see if he can't arrange something between everyone.

I've talked to Mike, he is busy, so I'll be doing the meeting arrangement.

If you or anyone else who wants to be there but isn't on the email chain please let me know.

October 13
On 10/12/24 07:56, Manu wrote:
> 
> The proposal in the DIP is very simple; struct rvalues are ref too now, so don't worry about the ref stuff; everything's a ref. The problem to be solved is, how do we appropriately distinguish an rvalue from an lvalue; and while we've had a myriad of proposals adding attributes, Walter found an arrangement where the distinction can be expressed in existing language in an astonishingly elegant way; recognise that by- value calls (accepts rvalue) are all actually move opportunities.
> 
> void f(ref T) // arg is an lvalue; the syntax says "I have received a reference to /someone else's/ thing"; or put another way, the callee does NOT own the argument.
> void f(T) // arg is an rvalue; this syntax says "I have received this thing"; the callee owns the argument, and as such, is a valid recipient of any move operation.
> In order to make move operations actually move operations, they need to be passed by ref (by /rvalue-ref/, so to speak), and that is literally the entire point of the DIP; the calling convention is adjusted so a by- value (r-value) parameter is passed by rvalue-ref.
> 
> This is what I mean where I say we're talking about "move semantics", but everyone seems to be fixated on move constructors as if they're an extraordinarily interesting part of this story.

I buy this except:

- With DIP1040, a move constructor `this(S)` is actually fundamentally different from a function `f(S)`, and not just because it is a constructor.

I think this should be adjusted so it works the way you say. Then there can be some special syntax to elide destructor calls explicitly.


- Move and copy constructors are indeed a bit special because the compiler may implicitly call them in ways it would not call any other constructor.

Here, idk. It's not really an important concern to me personally but I can see why someone might have an issue with this.

For copy constructors, consider:

```d
import std.stdio;

struct S{
    this(int x){ writeln("constructed"); }
    this(ref S){ writeln("copied"); }
}

void foo(S s){}

void main(){
    S s=2; // ok, actually does `S s=S(2)`
    S t=s; // ok, actually does `S s=S(s)`
    // foo(2); // error, refuses to call `foo(S(s))` to convert to `int`
    foo(s); // ok, calls foo(S(s)) to convert to rvalue
}
```

For move constructors, consider:

```d
import std.stdio;

struct S{
    size_t address;
    this(int){ address=cast(size_t)&this; }
    this(S){ writeln("rvalue constructor"); }
}

S foo(bool x){
    S s=2,t=2;
    if(x) return s;
    else return t;
}

void main(){
    auto s=foo(true); // (no output)
    auto t=foo(false); // (no output)
    writeln(s.address," ",cast(size_t)&s); // (two distinct numbers)
    writeln(t.address," ",cast(size_t)&t); // (two distinct numbers)
}
```

So with the compilation strategy that DMD currently uses for this code, it would need to start calling what is currently an rvalue constructor, but at the moment nothing is called. This is a change in behavior.

To me this seems desirable, but maybe there is some code out there that does not expect rvalue constructors to be called in this fashion?

Perhaps there should be a deprecation period?
October 13
On 10/13/24 00:43, Timon Gehr wrote:
> 
> - Move and copy constructors are indeed a bit special because the compiler may implicitly call them in ways it would not call any other constructor.

(Also, it implicitly synthesizes them.)
October 13
On 10/13/24 00:43, Timon Gehr wrote:
>      // foo(2); // error, refuses to call `foo(S(s))` to convert to `int`

(Should say: "convert to `S`" or "convert from `int`".)
1 2 3 4 5 6 7
Next ›   Last »