149

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

182

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.

8
  • 19
    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 Commented 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 Commented Sep 2, 2019 at 17:26
  • 5
    Are you sure your "function memoryTest(" example is correct?
    – Long Field
    Commented Jun 8, 2020 at 1:28
  • 1
    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
    Commented Apr 14, 2022 at 4:29
  • 2
    Can you please elaborate on the difference between string memory and string calldata in a function's return type? Commented May 28, 2022 at 23:19
15
  • 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.

4
  • 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?
    – wongx
    Commented May 5, 2022 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
    Commented May 9, 2022 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
    Commented Aug 11, 2022 at 15:49
  • What about the return types of an external function (which is returning a storage type), because you can only select between storage and memory in such case? Commented May 3, 2023 at 12:08

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.