0

Solidity documentation 0.8.14:

push():

Dynamic storage arrays and bytes (not string) have a member function called push() that you can use to append a zero-initialised element at the end of the array. It returns a reference to the element, so that it can be used like x.push().t = 2 or x.push() = b.

My contract:

pragma solidity ^0.8.0;

contract Demo {
    uint[] public storageDynamicUintArray;

    struct A {
        uint a;
    }
    A[] public storageDynamicArrayOfA;

    function pushToStorageDynamicUintArray() public {
        require(storageDynamicUintArray.length == 0, "storageDynamicUintArray.length == 0");
        
        uint item = storageDynamicUintArray.push(); // item is reference or new variable?
        require(storageDynamicUintArray.length == 1, "storageDynamicUintArray.length == 1");
        item = 1;
        require(item == 1, "item == 1");
        require(storageDynamicUintArray[0] == 0, "storageDynamicUintArray[0] == 0");
    }

    function pushToStorageDynamicArrayOfA() public {
        require(storageDynamicArrayOfA.length == 0, "storageDynamicArrayOfA.length == 0");
        
        A memory memoryItem = storageDynamicArrayOfA.push(); // item is reference or new variable?
        require(storageDynamicArrayOfA.length == 1, "storageDynamicArrayOfA.length == 1");
        memoryItem.a = 1;
        require(memoryItem.a == 1, "memoryItem.a == 1");
        require(storageDynamicArrayOfA[0].a == 0, "storageDynamicArrayOfA[0].a == 0");

        A storage storageItem = storageDynamicArrayOfA.push(); // item is reference!
        require(storageDynamicArrayOfA.length == 2, "storageDynamicArrayOfA.length == 2");
        storageItem.a = 2;
        require(storageItem.a == 2, "storageItem.a == 2");
        require(storageDynamicArrayOfA[1].a == 2, "storageDynamicArrayOfA[1].a == 2");
    }
}

In case uint array - push() retuns looks like a new variable. Not reference. In case A array - push() retuns looks like a new variable if I using memory location for variable.

Does the documentation look wrong?

1 Answer 1

0

You are mixing storage references with memory references. When the doc states :

It returns a reference to the element

It's a storage reference, since .push() is only valid on dynamic storage arrays (at least currently).

However, when you take that storage reference as a memory variable (which is in itself a reference to a memory location to be precise) then some special rules apply as described in the documentation :

Assignments between storage and memory (or from calldata) always create an independent copy.

And :

Assignments from storage to a local storage variable also only assign a reference.

So, going over the 3 cases that you have using the rules above :

Case 1 :

uint item = storageDynamicUintArray.push(); assigns a storage reference (.push()) to a local uint variable living on the stack. This is an independent copy by definition.

Case 2 :

A memory memoryItem = storageDynamicArrayOfA.push(); assigns a storage reference to a memory variable, this is also an independent copy as per the first rule.

Case 3 :

A storage storageItem = storageDynamicArrayOfA.push(); assigns a storage reference to a local storage variable, this is a reference as per the second rule.

The documentation is not wrong, it's just that the very specific portion you were reading did not mention the caveats of data location and assignment behavior.

I hope that answers your question.

2
  • Do I understand correctly that I can't use reference case 1? Copy only. Because I can't declare uint storage variable inside function. uint storage c = storageDynamicUintArray.push(); TypeError: Data location can only be specified for array, struct or mapping types, but "storage" was given.
    – Mike
    Jun 7, 2022 at 16:15
  • You can wrap the uint into a struct, it won't take any more space than the bare uint but will allow you to use a reference since it's wrapped into a struct.
    – hroussille
    Jun 8, 2022 at 6:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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