15

I have the following contract code example:

contract C {

    struct A {
        uint256 a;
        uint256 b;
    }

    struct B {
        A ax;
        uint256 c;
    }

    struct C {
        string name;
        B[] bs;
    }

    function init() {
        C memory c;
        B memory b;
        A memory a;

        a.a = 10;
        a.b = 20;

        b.ax = a;
        b.c = 30;

        c.name = "Test test test";
        c.bs[0] = b;
    }
}

Why can't I use push for the last statement

 c.bs[0] = b;

:

c.bs.push(b);

It throws the following error:

Untitled:30:9: Error: Member "push" is not available in struct B memory[] memory outside of storage.
        c.bs.push(b);
        ^-------^

but bs is an array of structures.

Sebi
  • 5,294
  • 6
  • 27
  • 52
  • 2
    Not completely related to the original question but to comment on Roland's comment: > Memory arrays have always a fixed length. Memory arrays can have variable length by initializing them with the new keyword. http://solidity.readthedocs.io/en/develop/types.html#arrays – atc Aug 16 '17 at 21:08

2 Answers2

19

Push is available only on storage arrays, that is member/ state variables and not in memory arrays, that is local variables:

push: Dynamic storage arrays and bytes (not string) have a member function called push that can be used to append an element at the end of the array. The function returns the new length.

http://solidity.readthedocs.io/en/latest/types.html

Roland Kofler
  • 11,638
  • 3
  • 44
  • 83
  • So it's not possible to initialize a struct that contains an array and is stored in memory and then later append it as an element to an array in storage? – Sebi Jul 19 '16 at 15:26
  • 2
    from what I understand this is perfectly possible using push, but not the other way around. Memory arrays have always a fixed length. – Roland Kofler Jul 19 '16 at 15:33
10

Explaining further what atc mentioned in their comment,

Fixed vs variable length

  • Memory arrays have fixed length, which means their length cannot be modified after it is initialized. Since push() appends a new element at the end of the array, it is not available for memory arrays.

  • Storage arrays, on the other hand, can have variable length. Yet, they're more expensive. Do you have to use storage arrays for your use case? Maybe not; keep reading.

Static vs dynamic length

  • Static-length arrays are initialized with a length defined at compile time, which is specified inside the array's square brackets. If you want to initialize them with a length that's not defined at compile time, you'll get an error:
function bar(uint baz) public {
    uint[7] memory foo1; // this is fine
    uint[7] storage foo2; // this is fine
    uint[baz] memory foo3; // this throws a compile-time error
    uint[baz] storage foo4; // this throws a compile-time error
}

As you can see, this applies for both memory and storage arrays.

  • Dynamic-length arrays are initialized with a length defined at runtime, which is specified by means of the new keyword and written inside parentheses after the array's square brackets:
function bar(uint baz) public {
    uint[] memory foo1 = new uint[](7); // this is fine
    uint[] storage foo2 = new uint[](7); // this is fine
    uint[] memory foo3 = new uint[](baz); // this is fine
    uint[] storage foo4 = new uint[](baz); // this is fine
}

e18r
  • 728
  • 8
  • 17