Jump to page: 1 2 3
Thread overview
Is "auto t=T();" not the same as "T t;"?
Oct 25, 2022
Andrey Zherikov
Oct 25, 2022
Kagamin
Oct 25, 2022
Adam D Ruppe
Oct 25, 2022
Ali Çehreli
Oct 25, 2022
Andrey Zherikov
Oct 25, 2022
Ali Çehreli
Oct 25, 2022
Andrey Zherikov
Oct 25, 2022
Salih Dincer
Oct 25, 2022
Paul Backus
Oct 25, 2022
Salih Dincer
Oct 25, 2022
Ali Çehreli
Oct 25, 2022
Ali Çehreli
Oct 25, 2022
Ali Çehreli
Oct 25, 2022
Paul Backus
Oct 25, 2022
Ali Çehreli
Oct 25, 2022
Paul Backus
Oct 25, 2022
matheus
Oct 25, 2022
Ali Çehreli
Oct 26, 2022
Salih Dincer
Oct 26, 2022
H. S. Teoh
Oct 26, 2022
Salih Dincer
Oct 26, 2022
Ali Çehreli
Oct 26, 2022
Salih Dincer
Oct 26, 2022
Andrey Zherikov
Oct 26, 2022
Kagamin
Oct 26, 2022
Ali Çehreli
October 25, 2022

I have the following types (simplified version of my code):

struct A
{
    int[] i;
}
struct B
{
    A[] a = [A.init];
}

This code:

    auto b1 = B.init;
    b1.a[0].i ~= 1;
    b1.a ~= A.init;
    b1.a[0].i ~= 11;
    b1.a[1].i ~= 12;
    b1.writeln;

    auto b2 = B();
    b2.writeln;

prints this as expected:

B([A([1, 11]), A([12])])
B([A([])])

But this code:

    B b1;      // auto b1 = B.init;
    b1.a[0].i ~= 1;
    b1.a ~= A.init;
    b1.a[0].i ~= 11;
    b1.a[1].i ~= 12;
    b1.writeln;

    B b2;     // auto b2 = B();
    b2.writeln;

prints this which is not expected:

B([A([1, 11]), A([12])])
B([A([1])])

Does the second piece of code shows a bug or my expectation is not correct (and why if so)?

October 25, 2022

There's a bug that an array field initializer is stored in the data section and thus is implicitly shared. Maybe the constructor form allocates in on spot?

October 25, 2022
On Tuesday, 25 October 2022 at 13:51:30 UTC, Andrey Zherikov wrote:
>     A[] a = [A.init];

This is a problem - this is referring to a static array instance, shared across all copies of B. You almost certainly don't want this.

That B.a[0] is the *same object* across different default-constructed Bs... unless the optimizer hits it or something.

But just don't do this. Only basic values and immutable strings are good to initialize this way. With the array or class objects, you're liable to get some shared thing.

If you change this to be initialized in a constructor (which will require an argument in D) or factory function, you'll get far more consistent behavior as each instance will have its own array.

As for why B() and B.init are different here... i don't know, probably some subtly of the compiler's implementation.
October 25, 2022
On 10/25/22 07:53, Adam D Ruppe wrote:
> On Tuesday, 25 October 2022 at 13:51:30 UTC, Andrey Zherikov wrote:
>>     A[] a = [A.init];
>
> This is a problem - this is referring to a static array instance, shared
> across all copies of B. You almost certainly don't want this.

Agreed. It should be fine when the elements are immutable as I've experimented with recently[1]:

struct Xml {
    string beg;
    string end = "/>";  // Shared by all instances;
                        // no allocation for some objects.
// ...
}

> As for why B() and B.init are different here... i don't know, probably
> some subtly of the compiler's implementation.

I think it's a bug.

Ali

[1] https://youtu.be/0JL9uT_XGZE?t=4260s

October 25, 2022

On Tuesday, 25 October 2022 at 14:53:50 UTC, Adam D Ruppe wrote:

>

But just don't do this. Only basic values and immutable strings are good to initialize this way. With the array or class objects, you're liable to get some shared thing.

If you change this to be initialized in a constructor (which will require an argument in D) or factory function, you'll get far more consistent behavior as each instance will have its own array.

I'd like to tune default ctor but structs can't have custom one.
Adding a ctor with parameter seems a hack to me - and compiler still allows default construction even when default ctor is disabled:

struct A
{
    int[] i;
}
struct B
{
    A[] a;
    @disable this();
    this(bool)
    {
	    A[] a = [A.init];
    }
}
void main()
{
    auto b1 = B.init;
    b1.a[0].i ~= 1;
    b1.a ~= A.init;
    b1.a[0].i ~= 11;
    b1.a[1].i ~= 12;
    b1.writeln;

    auto b2 = B.init;
    b2.writeln;
}

This fails in run time, not compile time:

core.exception.ArrayIndexError@onlineapp.d(19): index [0] is out of bounds for array of length 0
----------------
??:? _d_arraybounds_indexp [0x55b558b8ec55]
./onlineapp.d:19 _Dmain [0x55b558b6bd5f]
>

As for why B() and B.init are different here... i don't know, probably some subtly of the compiler's implementation.

Actually auto b = B.init; behaves the same way as auto b = B(); but they don't do the same as B b;

October 25, 2022

On Tuesday, 25 October 2022 at 14:53:50 UTC, Adam D Ruppe wrote:

>

On Tuesday, 25 October 2022 at 13:51:30 UTC, Andrey Zherikov wrote:

>
A[] a = [A.init];

This is a problem - this is referring to a static array instance, shared across all copies of B. You almost certainly don't want this.

That B.a[0] is the same object across different default-constructed Bs... unless the optimizer hits it or something.

Is it a bad idea to trigger copy on write before modification of B.a so it behaves as below?

    B b1;
    b1.a = b1.a.dup;   // copy on write
    b1.a[0].i ~= '1';
    b1.a ~= A.init;
    b1.a[0].i ~= '2';
    b1.a[1].i ~= '3';
    b1.writeln;        // B([A("12"), A("3")])

    B b2;
    b2.writeln;        // B([A("")])
October 25, 2022

On Tuesday, 25 October 2022 at 13:51:30 UTC, Andrey Zherikov wrote:

>

Does the second piece of code shows a bug or my expectation is not correct (and why if so)?

This is a bug:

void main()
{
  struct B
  {
    struct A
    {
      int i = 10;
    }
    A[] a = [A.init];
  }

  B[2] b;
  assert(b[0].a[0].i == 10);
  assert(b[1].a[0].i == 10);

  b[0].a[0].i = 1;
  assert(b[0].a[0].i == 1); // ok...
  assert(b[1].a[0].i == 1); // must be 10 !!!
}

SDB@79

October 25, 2022

On Tuesday, 25 October 2022 at 16:52:48 UTC, Salih Dincer wrote:

>

On Tuesday, 25 October 2022 at 13:51:30 UTC, Andrey Zherikov wrote:

>

Does the second piece of code shows a bug or my expectation is not correct (and why if so)?

This is a bug:

void main()
{
  struct B
  {
    struct A
    {
      int i = 10;
    }
    A[] a = [A.init];
  }

  B[2] b;
  assert(b[0].a[0].i == 10);
  assert(b[1].a[0].i == 10);

  b[0].a[0].i = 1;
  assert(b[0].a[0].i == 1); // ok...
  assert(b[1].a[0].i == 1); // must be 10 !!!
}

It's not a bug. They're pointing to the exact same instance of A in memory:

void main()
{
  struct B
  {
    struct A
    {
      int i = 10;
    }
    A[] a = [A.init];
  }

  B[2] b;
  assert(b[0].a.ptr is b[1].a.ptr);
}

As explained in Adam's reply, what happens here is that there is a single, global A[] allocated at compile time, which is shared between all instances of B.init. It's the same as if you'd written

struct B
{
    struct A
    {
        int i = 10;
    }
    static A[] globalArray = [A.init];
    A[] a = globalArray;
}
October 25, 2022
On 10/25/22 08:50, Andrey Zherikov wrote:

> I'd like to tune default ctor but structs can't have custom one.
> Adding a ctor with parameter seems a hack to me

There is static opCall, which may be seen as a hack as well. :) The following all print the same thing now:

import std.stdio;

struct A
{
    int[] i;
}
struct B
{
    A[] a = [A.init];

    static B opCall()
    {
        return B.init;
    }
}
void main()
{
    auto b1 = B.init;
    b1.writeln;

    B b2 = B();
    b2.writeln;

    B b3;
    b3.writeln;
}

> This fails in run time

Not anymore with the above code.

Ali

October 25, 2022

On Tuesday, 25 October 2022 at 17:18:35 UTC, Paul Backus wrote:

>

It's not a bug. They're pointing to the exact same instance of A in memory:

I don't understand? So I don't understand why it causes problems with dynamic arrays! So why is there nothing wrong with the static array in the example below?

import std.stdio, std.format;
void main()
{
  struct B
  {
    struct A {
      int i = 10;
    }
    //A[] a = [A.init];/*
    A[1] a = [A.init];//*/

    string toString() {
      return a[0].i.format!"%s";
    }
  }

  B[2] b;
  b.writeln;  // [10, 10]

  b[0].a[0].i = 0;
  b.writeln;  // [0, 10]

  b[1].a[0].i = 1;
  b.writeln;  // [0, 1]
}
« First   ‹ Prev
1 2 3