1

As I understand it 'memory' in the EVM is a byte array and cannot be dynamically resized, whereas 'storage' is able to be resized. What is happening when a parameter is declared as storage. Where is this storage written to?

Also is my assumption correct that when a 'memory' array is passed in as a parameter, it has a fixed size?

1

As I understand it 'memory' in the EVM is a byte array and cannot be dynamically resized, whereas 'storage' is able to be resized. What is happening when a parameter is declared as storage. Where is this storage written to?

When a parameter marked storage is passed to a function, what is being passed is a reference to some data that already exists in storage. Consider the following code:

pragma solidity 0.5.2;

contract Test {
    uint256[] public foo;

    function test() external {
        uint256 oldLength = foo.length;

        append(foo);

        assert(foo.length == oldLength + 1 && foo[oldLength] == 42);
    }

    function append(uint256[] storage arr) internal {
        arr.push(42);
    }
}

Here the foo array is left in storage the whole time. append can modify the passed in array.

Also is my assumption correct that when a 'memory' array is passed in as a parameter, it has a fixed size?

In-memory arrays passed in as parameters can be either fixed size or dynamic size, but I think what you're getting at is that they cannot be resized, and you're right about that. In-memory arrays cannot be resized in general, and this includes arrays that are passed as memory parameters. This is simply due to the difference between memory layout and storage layout. See the Solidity documentation on storage layout and memory layout for more detail.

  • Thank you that was very clear. Can you clarify the difference between dynamic and fixed size arrays? I assumed it was always impossible to resize fixed size arrays. – arete Jan 9 at 15:53
  • Fixed-size arrays look like uint256[5] foo. The size is part of the type, and so there's no need to separately store a length. A dynamically-sized array looks like uint256[] foo and is prefixed in memory/storage with a length. (And in storage, that length can be updated.) – user19510 Jan 9 at 15:59
2

Also is my assumption correct that when a 'memory' array is passed in as a parameter, it has a fixed size?

No. A dynamic array is preceded by a uint that specifies the length, e.g. the following array has 3 elements. The input would come in four chunks, one for the length (3) and three for the elements that follow.

I made this example to show that dynamic memory work as both function inputs and outputs.

pragma solidity 0.5.2;

contract Memory {

    function doSomething(uint[] memory array) public pure returns(uint[] memory y) {
        return array;
    }
}

What is happening when a parameter is declared as storage. Where is this storage written to?

As a developer, it may be sufficient to know that the values are written to a namespace with a "slot" for each index (as well as the length for a dynamic array).

If you are not familiar with mappings they are a more direct interface to the namespace that uses a hash function to compute the "slot". So ...

mapping(uint => bool) flags;

basically says "for every possible uint, compute a key and store a bool there (if set)." All keys exist but the default is zero/false and the majority of the values will never be set. It doesn't initialize the "empty" slots (that would take an enormous amount of space). If the empty slots are inspected, it returns 0, false, empty, null.

The reason I mention this is deep down, dynamic arrays use the same hash table namespace scheme, where the "rows" are used to generate keys ... there is a key for row 0, a key for row 1, a key for row 2, etc. as well as a length (uint). Length puts a boundary on the indexes so it can detect "out of bounds" exceptions.

If you want to get into the guts of how storage actually works, have a look at this: ELI5 How does a Merkle-Patricia-trie tree work?

For completeness, I would add that the storage state is a logical construct. Clients are free to implement physical storage by any scheme they wish, so exploration of physical storage details will branch out on a case-by-case basis. In terms of writing contracts (and assembler), you would rummage around in the logical storage, so it's enough to understand the logical structure in most cases.

Hope it helps.

  • Thanks for that link. Very interested in learning more about patricia trie's. – arete Jan 9 at 15:52

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.