Skip to content

Variable Types and Data Locations in Solidity

This example demonstrates the different variable types (storage, memory, calldata) and constant/immutable variables in Solidity.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract VariableTypes {
    // Storage Variables - Persistent state variables
    string public storedData = "This is stored in blockchain storage";
    uint256[] public numbers;

    // Constant Variable - Value fixed at compile time
    // Gas efficient as value is replaced during compilation
    uint256 public constant MAX_NUMBERS = 100;

    // Immutable Variable - Can be set once in constructor
    // Gas efficient as value is replaced during deployment
    address public immutable DEPLOYER;

    constructor() {
        DEPLOYER = msg.sender;
        numbers.push(1);  // Initialize storage array
    }

    // Function demonstrating memory vs calldata for parameters
    // Calldata is read-only and more gas efficient for parameters
    function processString(string calldata _text) public pure returns (string memory) {
        // Cannot modify _text as it's calldata
        return _text;
    }

    // Function demonstrating memory usage
    // Memory is mutable but temporary
    function concatenateString(string memory _text) public view returns (string memory) {
        // Create new string in memory
        string memory result = string(
            abi.encodePacked(storedData, " + ", _text)
        );
        return result;
    }

    // Function demonstrating storage vs memory
    function updateAndReturn(uint256 newNumber) public returns (uint256[] memory) {
        // Storage reference - modifies blockchain state
        numbers.push(newNumber);

        // Memory array - temporary copy
        uint256[] memory tempArray = new uint256[](numbers.length);
        for(uint i = 0; i < numbers.length; i++) {
            tempArray[i] = numbers[i];
        }

        return tempArray;
    }
}

Key Concepts

  1. Storage Variables

    • Stored permanently on the blockchain
    • Most expensive in terms of gas
    • Persist between function calls
  2. Memory Variables

    • Temporary storage that lasts only during function execution
    • Less expensive than storage
    • Can be modified within functions
  3. Calldata

    • Read-only temporary storage
    • Most gas efficient
    • Used mainly for function parameters
  4. Constant Variables

    • Must be initialized at declaration
    • Value replaced at compile time
    • Very gas efficient
  5. Immutable Variables

    • Can be set once in constructor
    • Value replaced at deployment
    • Gas efficient like constants

Best Practices

  1. Use calldata for function parameters that don't need to be modified
  2. Use memory for temporary data structures
  3. Use storage only when state needs to persist
  4. Use constant for values known at compile time
  5. Use immutable for values that can be set once at deployment

Try it yourself in the Remix IDE: Open in Remix