1

Recently I was going through

https://docs.soliditylang.org/en/v0.8.13/types.html#data-location-and-assignment-behaviour

which explains the data locations and its behaviour..

there in the given code example I have come across

function g(uint[] storage) internal pure {}

function h(uint[] memory) public pure {}

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;

contract C {
    // The data location of x is storage.
    // This is the only place where the
    // data location can be omitted.
    uint[] x;

    // The data location of memoryArray is memory.
    function f(uint[] memory memoryArray) public {
        x = memoryArray; // works, copies the whole array to storage
        uint[] storage y = x; // works, assigns a pointer, data location of y is storage
        y[7]; // fine, returns the 8th element
        y.pop(); // fine, modifies x through y
        delete x; // fine, clears the array, also modifies y
        // The following does not work; it would need to create a new temporary /
        // unnamed array in storage, but storage is "statically" allocated:
        // y = memoryArray;
        // This does not work either, since it would "reset" the pointer, but there
        // is no sensible location it could point to.
        // delete y;
        g(x); // calls g, handing over a reference to x
        h(x); // calls h and creates an independent, temporary copy in memory
    }

    function g(uint[] storage) internal pure {}
    function h(uint[] memory) public pure {}
}

I would like to understand why do we need to pass a state variable as storage or memory in contract functions, when it is alraedy globally availble in the same contract.

1
  • 1
    That was only an example in the documentation. But sometimes, it's useful to receive storage objects to an internal function. As you mentioned, you already have them available in the state of the smart contract, but not always a utility function knows with which object to work. Sometimes we have struct instances in an array or map in the state, and we need to do some actions on one or some of them, so we pass them to a specialized function that can do those changes. Passing state objects as memory would make a copy and not modify the original, passing them as storage will modify them. Aug 11, 2022 at 5:20

1 Answer 1

1

storage or memory tells the function where the parameter is expected to come from. If the parameter is of storage type, then you get a reference to the array, i.e a pointer. If it is a memory type, you get a copy depending on how it was called.

Consider the following example to understand one of the benefits.

function takeStorageArray(uint[] storage arr) view

Given the above function, since the parameter is a storage pointer and you intend the function to be view, solidity can perform checks to ensure the function is actually view, doesn't modify the array reference, thereby modifying storage.

function takeMemoryArray(uint[] memory arr) internal {
  // do something with arr
}
function invokeTakeMemoryArray() external {
 uint[] memory memArray = new uint[](10);
 takeMemoryArray(memArray);
}

In the above example, because the parameter is a memory array and invokeTakeMemoryArray passed in a memory array, you get a reference with no copy cost.

Below example would create a copy in memory and pass it, incurring a copy cost.

function takeMemoryArray(uint[] memory arr) internal {
  // do something with arr
}
function invokeTakeMemoryArray() external {
 takeMemoryArray(aStorageArray);
}

The main idea is that functions define their parameter locations according to the logic they try to implement. A view function looping over an array to check duplicates would take a memory array. A state validation function that validates a storage array would take in storage reference.

Defining parameter locations also depend on where the developer believes the array comes from. Done right, it saves a lot of copy cost, thereby gas cost for users.

1
  • Hi Pranay, Thxs for the details. if the internal fun access statevariable without being passes then also it ll be accesing it as ref Correct? What difference it ll make like Contract Test { uint[5] myArray = [0,1,2,3,4]; function getArrayValue(uint index) public view returns(uint) { uint result = _readArray(index); return result; } function _readArray(uint _index) private return (uint){ return myArray[index]; } } So in this case I could access the state variable array without passing it what diff it would have been made if passed as storage.
    – CaptPython
    Aug 12, 2022 at 5:36

Your Answer

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

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