7

Is there a mistake in the way I initialize Bar b in the function foobar?

contract Foo {

    struct Bar {
        address owner;
        uint[] x;
    }

    Bar[] public bars;

    function foobar(address a) public {
        Bar storage b = Bar(a, new uint[]) // will that be an array in storage?
        bars.push(b)
    }

}
14

There is no need to initialize storage arrays in Solidity. Only memory arrays has to be initialized before usage.

So in your case, no need to initialize x inside Bar as long as you are not assigning a value to one of the x indexes inside your foobar. Actually, making initialization in your code will consume gas for no reason.

The following code works well for your case:

function foobar(address a) public {
    Bar memory b;
    b.owner = a;
    //When 'b' is pushed to 'bars' array:
    // (1) 'b' will be converted from memory to storage.
    // (2) And 'x' inside it will be initialized automatically.
    bars.push(b); 
}

However, if you need to access x and push some value you can use push:

function foobar2(address a, uint x0) public {
    Bar memory b;
    b.owner = a;
    bars.push(b);
    //Trying: b.x[0] = x0; will generate error. Since, b.x is a memory array that is not initialized!
    bars[bars.length - 1].x.push(x0); //This will work fine!
}

Actually, you can still initialize your memory array, as an empty one, as follow:

function foobar3(address a) public {
    Bar memory b = Bar(a, new uint[](0)); //Thanks to "James Duffy" for his answer.
    bars.push(b);
}

Last thing to mention is that: If you have multi values, that you need to insert to your x array, then you can do this as follow:

function foobar4(address a, uint[] _x) public {
    Bar memory b = Bar(a, _x);
    bars.push(b);
}

Or as follow. But, this will consume more gas:

function foobar5(address a, uint[] _x) public {
    Bar memory b;
    b.owner = a;
    bars.push(b);

    Bar storage c = bars[bars.length - 1]; // Get the newly added instance of the storage struct
    for (uint i = 0; i < _x.length; i++) {
        c.x.push(_x[i]);
  }

Check full code at the nice EthFiddler: https://ethfiddle.com/fQI6Khgz3E

  • Welcome. And thanks to Georgios Konstantopoulos and Loom Network: medium.com/loom-network/… – Muhammad Altabba Feb 20 '18 at 12:01
  • After calling foobar, foobar2 or foobar3, I get value of bars[0] == {owner: address} without property x at all!!! It's completely ignored. How is it possible? What am I doing wrong? – Artod Mar 8 '18 at 17:06
  • 1
    I figured out why this is happening. Need to have separate getter in order to receive arrays from structs like getXFromBar – Artod Mar 8 '18 at 17:45
2

Working fiddle:

https://ethfiddle.com/Yn6fLiAjto

One way to make this work is to create your temporary Bar in memory before pushing it to bars (Bar memory b instead of Bar storage b). Solidity will then automatically copy the struct data from memory to storage. See: https://ethereum.stackexchange.com/a/4476/22415 for more details.

Also new uint[] is a function which requires a size argument, e.g. new uint[](8).

So in full, that line should read Bar memory b = Bar(a, new uint[](8));

  • 1
    I see! So I cannot assign a dynamically sized array to the struct while initializing it? – Manan Mehta Nov 16 '17 at 18:44
  • any answers yet? – Manan Mehta Nov 21 '17 at 21:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.