Cover photo

Reference Types and Data Locations in Solidity

Reference Types

In Solidity, some types are very simple so that when you use them (such as declaring variables, calling functions, etc), they are just copied. These types include int, uint, bool, address, and they are usually called value types.

On contrast, when you use other complicated types (sturct, array, mapping), you must be carefully to make sure that if you are creating a reference to it, or you are copying it from one data location to another. A reference is the same as a pointer in some other languages. It’s cheap, but when you modify a referent, the referenced value will also be modified, because you are changing the underlying value.

Data Locations

The reference types can be copied between three data locations, and when you use reference types, you must explicitly provide the data area.

  • memory - Whose lifetime is limited to a function call. It is initialized as a clean area at the beginning of a function call, and will be cleared at the end of the function call.

  • storage - State variables are stored here, and their lifetime is limited to the lifetime of the contract. This is the most expensive one.

  • calldata - Special data location that contains the function arguments. It is read-only, so if you need to modify the arguments, you can use memory so that it will copy the arguments from calldata to memory. This one is the cheapest.

Assignment Behavior

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

  • Assignments from memory to memory only create references. This means that changes to one memory variable are also visible in all other memory variables that refer to the same data.

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

  • All other assignments to storage always copy. Examples for this case are assignments to state variables or to members of local variables of storage struct type, even if the local variable itself is just a reference.

e.g.

contract A {
    // The data location of x is storage
    // State variables' data locations can be ommited
    uint[] x;

    // `argArray` is copied from `calldata` to `memory`
    function f(uint[] memory argArray) public {
        // Copy from `memory` to `storage`
        x = argArray;
        // Data location of y is `storage`
        // y is a reference (or pointer) to x
        // Any modifying of x or y influence the other
        uint[] storage y = x;
        // Copy from `storage` to `memory`
        uint[] memory z = x;

        // Handling over a reference of x to the function
        g(x);
        // Creates a copy from `storage` to `memory`
        h(x);
    }

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

    function h(uint[] memory b) internal {}
}