108

I have seen people use both memory and calldata keywords when writing Solidity. Specifically, they are used when declaring function parameters that take dynamic types like 'structs' or 'arrays'.

When should I use memory and when should I use calldata?

0

2 Answers 2

133

memory and calldata (as well as storage) are keywords that define the data area where a variable is stored. To answer your question directly, memory should be used when declaring variables (both function parameters as well as inside the logic of a function) that you want stored in memory (temporary), and calldata must be used when declaring an external function's dynamic parameters.

The easiest way to think about the difference is that calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory.


Breaking this down, let's first look at memory. memory's lifetime is limited to a function call and is meant to be used to temporarily store variables and their values. Values stored in memory do not persist on the network after the transaction has been completed. Some notable implementation details about memory are as follows:

  • It can be used for both function declaration parameters as well as within the function logic
  • It is mutable (it can be overwritten and changed)
  • It is non-persistent (the value does not persist after the transaction has completed)

This answer is a great resource to understand memory.

calldata is very similar to memory in that it is a data location where items are stored. It is a special data location that contains the function arguments, only available for external function call parameters. From the Solidity docs:

Calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory.

This is the cheapest location to use, but it has a limited size. In particular, that means that functions may be limited in their number of arguments.1 Notable implementation details about calldata are as follows:

  • It can only be used for function declaration parameters (and not function logic)
  • It is immutable (it can't be overwritten and changed)
  • It must be used for dynamic parameters of an external function
  • It is non-persistent (the value does not persist after the transaction has completed)

The following is a valid example of code using memory and calldata:

pragma solidity 0.5.11;

contract Test {
    
    string stringTest;
    
    function memoryTest(string memory _exampleString) public returns (string memory) {
        _exampleString = "example";  // You can modify memory
        string memory newString = _exampleString;  // You can use memory within a function's logic
        return newString;  // You can return memory
    }
    
    function calldataTest(string calldata _exampleString) external returns (string memory) {
        // cannot modify _exampleString
        // but can return it
        return _exampleString;
    }
}

Edit Based on the comment by Tjaden Hess

One good way to think about the difference and how they should be used is that calldata is allocated by the caller, while memory is allocated by the callee.

7
  • 14
    In what sense does calldata have limited size? Calldata is exactly the size of the data passed to the underlying EVM call, which can be as large as you want (bounded by the gas budget). I'd say that the difference between calldata and memory is that calldata is allocated by the caller, while memory is allocated by the callee Sep 1, 2019 at 21:44
  • 1
    "In what sense does calldata have limited size?" That is an oversight on my part. The limit is, like you said, either gas budget or stack depth limit. I will edit the answer. "calldata is allocated by the caller, while memory is allocated by the callee" This is a great way to put it Sep 2, 2019 at 17:26
  • 5
    Are you sure your "function memoryTest(" example is correct?
    – Long Field
    Jun 8, 2020 at 1:28
  • It has been updated with the correct variables. Jun 14, 2021 at 16:30
  • Prior to version 0.6.9 data location for reference-type arguments was limited to calldata in external functions, memory in public functions and either memory or storage in internal and private ones. Now memory and calldata are allowed in all functions regardless of their visibility.
    – frank
    Apr 14 at 4:29
4
  • memory variables are allocated by the callee and their value can be modified inside the function (they're mutable). You can declare a variable inside a function memory located as well as it's parameters.

All lines in this example are correct:

function foo(string memory a) public {
   string memory b = "abc";
   b = "cba";
}

  • calldata are only parameters of a function which is declared as external, which value is allocated by the caller, that's why it's gas cost is lower. For this reason only parameters of an external function can be declared as calldata (no variables declared inside the function and no parameters of a function which is not external)
// this is wrong because is being used in a public function
function foo(string calldata a) public { 
// this one line is ok
function foo(string calldata a) external {
   // this one is wrong
   string calldata b = "abc";
   // this one is also wrong
   a = "abc";
}

None of them are persistent, meaning they are deleted when the function is finished in opposition to storage variables.

3
  • Is memory used to reduce gas by having the parameter in memory? So essentially, memory should be declared whenever the method references the variable more than once. If not, what's the point of calling memory if we can just not call it?
    – wongz
    May 5 at 2:39
  • @wongz the 'memory' ones are the ones that cost the most gas, cause is the blockchain node the one using its space for them, and their allocation must be mutable. You should use calldata whenever possible (this is, a constant parameter in an external function).
    – R01010010
    May 9 at 15:32
  • But this also works function calls(bytes calldata callData) public returns (bytes4, bool), so what you wrote "For this reason only parameters of an external function can be declared as calldata" isnt correct or am I missing something?
    – Blissful
    Aug 11 at 15:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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