Black friday

Save big!

All courses under $5 - for a limited time!

Code has been added to clipboard!

The Guide to Assignment for Solidity Structs and Arrays

Reading time 4 min
Published Jul 3, 2019
Updated Sep 9, 2019

The assignment process assigns a value to a variable. It is more complex for Solidity structs and arrays. In this tutorial, we will explain the default values of variables, how to assign to state and local variables, and how to destructure assignments.

This tutorial pays special attention to assignment for non-value types (such as an array in Solidity). It also discusses scoping, which indicates the variable availability within a function and a contract.

Solidity Struct: Main Tips

  • Assignment sets values to variables.
  • Tuple types allow returning several values at once.
  • Assignment is complex for Solidity structs and arrays.
  • Since 0.5.0 version, Solidity follows different scoping rules than before.

Destructuring Assignments and Returning Multiple Values

Internally, Solidity permits tuple types. They are applied to retrieve several values simultaneously. After that, these values can be set to new variables or already existing ones.

Note: tuple types are lists of objects that might be of different types. Their numbers are constant during the compiling.

Example
pragma solidity >0.4.23 <0.7.0;

contract C {
    uint[] data;

    function f() public pure returns (uint, bool, uint) {
        return (7, true, 2);
    }

    function g() public {
        // Variables declared with type and assigned from the returned tuple,
        // not all elements have to be specified (but the number must match).
        (uint x, , uint y) = f();
        // Common trick to swap values -- does not work for non-value storage types.
        (x, y) = (y, x);
        // Components can be left out (also for variable declarations).
        (data.length, , ) = f(); // Sets the length to 7
    }
}

Remember: Solidity uses tuple types only for forming syntactic groupings and expressions.

Struct and Array Assignment

The assignment is complicated for Solidity arrays and structs. The process of assigning to a state variable generates an independent copy. When assigning to a local variable, it creates independent copies only for elementary types.

Note: elementary types are static ones, fitting into 32 bytes.

Assigning non-value types from a state variable to a local variable makes the local variable have a reference to the initial state variable. Another assignment to the local variable does not change the state (only the reference).

Remember: the state changes during assignment to members of the local variable.

The following example shows that the call to g(x) does not change x since it generates an independent copy of the storage value in memory. On the other hand, h(x) changes x since it creates only the reference, not the copy.

Example
pragma solidity >=0.4.16 <0.7.0;

contract C {
    uint[20] x;

    function f() public {
        g(x);
        h(x);
    }

    function g(uint[20] memory y) internal pure {
        y[2] = 3;
    }

    function h(uint[20] storage y) internal {
        y[3] = 4;
    }
}

Scoping and Declaration

The default value of variables is set for all types. Here is a short list:

  • bool has false.
  • uint and int 0.
  • Every separate element will be set to the default type value for the statically-typed array in Solidity and bytes1 to bytes32.
  • Dynamically-sized arrays, bytes, and strings have an empty array or string.
  • The default value for the enum is its first member.

After declaration, variables become visible until the end of the smallest { }-block, containing the declaration. However, variables defined as a part of a for-loop are visible until the end of the for-loop.

Note: when variables and other items are declared not in the code block, they become visible before the declaration. Such declaration can occur in functions, user-defined types and contracts.

The code below compiles without any issues because the two variables share the name, but do not have connected scopes:

Example
pragma solidity >=0.5.0 <0.7.0;
contract C {
    function minimalScoping() pure public {
        {
            uint same;
            same = 1;
        }

        {
            uint same;
            same = 3;
        }
    }
}

This example illustrates that the first assignment to x sets the outer and not the inner variable. As a result, a warning appears, stating that the outer variable is shadowed:

Example
pragma solidity >=0.5.0 <0.7.0;

contract C {
    function f() pure public returns (uint) {
        uint x = 1;
        {
            x = 2; // this will assign to the outer variable
            uint x;
        }
        return x; // x has value 2
    }
}

Note: as of Solidity 0.5.0 version, the conventions for scoping have changed and no longer resemble JavaScript. Now, variables declared in any place within a function won’t be in the scope for the whole function.

In the following example, we show that following the old rules generates an error in later versions of Solidity:

Example
pragma solidity >=0.5.0 <0.7.0;
// This will not compile
contract C {
    function f() pure public returns (uint) {
        x = 2;
        uint x;
        return x;
    }
}

Solidity Struct: Summary

  • During assignment, variables receive values.
  • Tuple types can deliver multiple values at once.
  • Array and struct Solidity types are more difficult than assigning values to elementary ones.
  • 0.5.0 version changed the rules of scoping, and they no longer resemble JavaScript scoping.