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.