www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Referencing structs in a foreach

reply "Alf" <alfyvr yahoo.ca> writes:
I am wondering what could be the mistake. When trying to modify 
the member of a struct from within a foreach, the changes are 
gone after leaving the loop.

Code:

import std.stdio;

void test()
{
   struct Foo
   {
     int a;
     int b;
   }

   struct Bar
   {
     Foo f1;
     Foo f2;
   }

   Bar bar = {{10, 20}, {10, 20}};

   writefln("Before => f1.a: %d, f1.b: %d - f2.a: %d, f2.b: %d\n", 
bar.f1.a, bar.f1.b, bar.f2.a, bar.f2.b);

   foreach (ref f; [bar.f1, bar.f2])
   {
     f.a++;
     f.b++;
   }

   writefln("After => f1.a: %d, f1.b: %d - f2.a: %d, f2.b: %d\n", 
bar.f1.a, bar.f1.b, bar.f2.a, bar.f2.b);
}

void main()
{
   test();
}

Should print:

Before => f1.a: 10, f1.b: 20 - f2.a: 10, f2.b: 20
After => f1.a: 11, f1.b: 21 - f2.a: 11, f2.b: 21

But prints:

Before => f1.a: 10, f1.b: 20 - f2.a: 10, f2.b: 20
After => f1.a: 10, f1.b: 20 - f2.a: 10, f2.b: 20

Thanks,

Alf
Jul 22 2014
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 23 July 2014 at 01:31:48 UTC, Alf wrote:
   foreach (ref f; [bar.f1, bar.f2])
This allocates new array and copies struct values to it (as D structs are value types). I think this should have been a compile-time error btw, it never makes sense to do ref iteration over an array literal for this very reason. Most likely you want to forced loop unrolling here and thus something like this:
   import std.typetuple;
   foreach (ref f; TypeTuple!(bar.f1, bar.f2))
(don't pay attention to the weird "TypeTyple" name, it lies)
Jul 22 2014
parent reply "Alf" <alfyvr yahoo.ca> writes:
Thanks for your reply.
I figured an easier way would be to simply build an array of 
references:

   foreach (ref f; [&bar.f1, &bar.f2])
   {
     f.a++;
     f.b++;
   }

It seems to work just fine.

Alf

On Wednesday, 23 July 2014 at 01:41:33 UTC, Dicebot wrote:
 On Wednesday, 23 July 2014 at 01:31:48 UTC, Alf wrote:
  foreach (ref f; [bar.f1, bar.f2])
This allocates new array and copies struct values to it (as D structs are value types). I think this should have been a compile-time error btw, it never makes sense to do ref iteration over an array literal for this very reason. Most likely you want to forced loop unrolling here and thus something like this:
  import std.typetuple;
  foreach (ref f; TypeTuple!(bar.f1, bar.f2))
(don't pay attention to the weird "TypeTyple" name, it lies)
Jul 23 2014
parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Wednesday, 23 July 2014 at 17:23:14 UTC, Alf wrote:
 Thanks for your reply.
 I figured an easier way would be to simply build an array of 
 references:

   foreach (ref f; [&bar.f1, &bar.f2])
   {
     f.a++;
     f.b++;
   }

 It seems to work just fine.
I'd recommend using std.range.only: foreach (ref f; only(&x, &y)) { f.a++; f.b++; } Using array literals introduces the possibility of an unnecessary heap allocation. Using only will never allocate.
Jul 23 2014
prev sibling parent "Dicebot" <public dicebot.lv> writes:
Also please post any further questions to 
http://forum.dlang.org/group/digitalmars.D.learn instead
Jul 22 2014