August 12, 2021

On Thursday, 12 August 2021 at 15:39:40 UTC, Learner wrote:

>

On Thursday, 12 August 2021 at 14:57:16 UTC, Steven Schveighoffer wrote:

>

[...]

It is not clear to me why the inout generated copy constructor of the B structure is not able to copy the A structure.

[...]

Why will copy constructor of struct B accept argument of type A?

August 12, 2021

On Thursday, 12 August 2021 at 15:50:05 UTC, Tejas wrote:

>

On Thursday, 12 August 2021 at 15:39:40 UTC, Learner wrote:

>

On Thursday, 12 August 2021 at 14:57:16 UTC, Steven Schveighoffer wrote:

>

[...]

It is not clear to me why the inout generated copy constructor of the B structure is not able to copy the A structure.

[...]

Why will copy constructor of struct B accept argument of type A?

You are right, I forgot the A member, now it is clear:

struct A
{
    int[] data;

    this(ref return scope           A rhs)            {}
    this(ref return scope const     A rhs) const      {}
    this(ref return scope immutable A rhs) immutable  {}
}

struct B
{
    // default generated copy constructor, by section 14.15.6.2
    this(ref return scope inout(B) src) inout
    {
        foreach (i, ref inout field; src.tupleof) this.tupleof[i] = field;
    }
    A a;
}
Error: none of the overloads of `__ctor` are callable using a `inout` object, candidates are:
`A.this(return ref scope A rhs)`
`A.this(return ref scope const(A) rhs)`
`A.this(return ref scope immutable(A) rhs)`

Thank you everybody.

August 12, 2021

On Thursday, 12 August 2021 at 15:39:40 UTC, Learner wrote:

>

It is not clear to me why the inout generated copy constructor of the B structure is not able to copy the A structure.

struct A
{
    int[] data;

    this(ref return scope           A rhs)            { /* body */ }
    this(ref return scope const     A rhs) const      { /* body */}
    this(ref return scope immutable A rhs) immutable  { /* body */}
}

struct B
{
    // default generated copy constructor, by section 14.15.6.2
    this(ref return scope inout(B) src) inout
    {
        foreach (i, ref inout field; src.tupleof) this.tupleof[i] = field;
    }
}

Can point me to a code example of when the D generated copy constructor fails to copy A, and why?

You have forgotten to add a member variable of type A to your B struct. If you add one, you will see the following error message:

onlineapp.d(18): Error: none of the overloads of `__ctor` are callable using a `inout` object, candidates are:
onlineapp.d(5):        `onlineapp.A.this(return ref scope A rhs)`
onlineapp.d(6):        `onlineapp.A.this(return ref scope const(A) rhs)`
onlineapp.d(7):        `onlineapp.A.this(return ref scope immutable(A) rhs)`

(Full example: https://run.dlang.io/is/9BrpZj)

Essentially, you cannot use a mutable, const, or immutable copy constructor to copy an inout object, only an inout copy constructor.

The reason for this is a bit subtle. Normally, inout can convert to const, so you might expect that the const copy constructor could be used to construct a copy of an inout object. However, copy constructors take their arguments by ref, and implicit conversions are not allowed for arguments passed to ref parameters. (I cannot find a citation in the spec for this, but you can verify it yourself.)

Here's a simplified example that gives the same error:

void f(inout(int)[] a)
{
    g(a);
}

void g(ref int[] a) {}
void g(ref const(int)[] a) {}
void g(ref immutable(int)[] a) {}
August 12, 2021

On Thursday, 12 August 2021 at 16:12:39 UTC, Paul Backus wrote:

>

On Thursday, 12 August 2021 at 15:39:40 UTC, Learner wrote:

>

[...]

You have forgotten to add a member variable of type A to your B struct. If you add one, you will see the following error message:

[...]

"implicit conversions are not allowed for arguments passed to ref parameters" was the point missing to me.

Good to know, and thank yo to everyone!

August 12, 2021
On 8/12/21 4:32 AM, Paul Backus wrote:

> Qualifying the ctor as `inout` works fine

I can see how a DConf Online presention is shaping up in your head. ;)

  http://dconf.org/2021/online/index.html

We need a collective understanding of effective use of such fundamental concepts.

Ali

August 13, 2021

On 8/12/21 12:12 PM, Paul Backus wrote:

>

The reason for this is a bit subtle. Normally, inout can convert to const, so you might expect that the const copy constructor could be used to construct a copy of an inout object. However, copy constructors take their arguments by ref, and implicit conversions are not allowed for arguments passed to ref parameters. (I cannot find a citation in the spec for this, but you can verify it yourself.)

implicit const conversions are possible via a single ref, but not through a double reference. In this case, it's not the passing of the inout object to the const constructor.

The issue is that you can't convert const (or immutable or mutable) to inout implicitly, and the member variable is inout inside an inout constructor. Therefore, there's no viable copy constructor to call for the member, and the outer copy constructor cannot be generated.

As a side note, inout actually can bind to double references of any mutability, unlike const, which is a nice feature that is seldom talked about.

-Steve

August 13, 2021

On Friday, 13 August 2021 at 15:26:15 UTC, Steven Schveighoffer wrote:

>

The issue is that you can't convert const (or immutable or mutable) to inout implicitly, and the member variable is inout inside an inout constructor. Therefore, there's no viable copy constructor to call for the member, and the outer copy constructor cannot be generated.

I'm not quite sure I follow this. Are you saying that the constructor call is typechecked as if it were written like this:

this.field = this.field.__ctor(rhs.field);

...and not like this?

this.field.__ctor(rhs.field);

Because I can see how the first version would involve an const-to-inout conversion, but the second version looks like it ought to work.

August 13, 2021

On 8/13/21 4:58 PM, Paul Backus wrote:

>

On Friday, 13 August 2021 at 15:26:15 UTC, Steven Schveighoffer wrote:

>

The issue is that you can't convert const (or immutable or mutable) to inout implicitly, and the member variable is inout inside an inout constructor. Therefore, there's no viable copy constructor to call for the member, and the outer copy constructor cannot be generated.

I'm not quite sure I follow this. Are you saying that the constructor call is typechecked as if it were written like this:

this.field = this.field.__ctor(rhs.field);

...and not like this?

this.field.__ctor(rhs.field);

Because I can see how the first version would involve an const-to-inout conversion, but the second version looks like it ought to work.

My point was just that ref inout normally binds to ref const.

Example:

void foo(ref const int a)
{
  writeln("hi, a is ", a);
}

void bar(ref inout int b)
{
   foo(b); // fine
}

You implied in your statement that it was the ref-ness that prevents the call. Your simplified example was also a bit off, it was a double indirection of a ref array (which is definitely forbidden to be implicit cast).

But for constructors it's not the same. Essentially because constructors have different rules for what they can do with their inputs (the inout this parameter can be assigned to for the member's first assignment).

What I was trying to say (poorly) is that inside the inout copy ctor, you can actually call the const A copy constructor with an input of the other inout A. You just can't call it on the member (or assign it to the member), because that would allow some bad things to happen in some cases.

-Steve

August 13, 2021

On Friday, 13 August 2021 at 21:34:29 UTC, Steven Schveighoffer wrote:

>

But for constructors it's not the same. Essentially because constructors have different rules for what they can do with their inputs (the inout this parameter can be assigned to for the member's first assignment).

What I was trying to say (poorly) is that inside the inout copy ctor, you can actually call the const A copy constructor with an input of the other inout A. You just can't call it on the member (or assign it to the member), because that would allow some bad things to happen in some cases.

Thanks; the special treatment of this is the part I was missing.

As far as I can tell there is no mention in the language spec of how this works. Probably worth documenting.

1 2 3
Next ›   Last »