Data Location and Assignment Behaviors
Every reference type contains information on where it is stored. There are three possible options: memory
, storage
, and calldata
. The set location is important for semantics of assignments, not only for the persistence of data:
storage
: The location type where the state variables are stored on blockchain which means types that has storage
location are persistent.
memory
: Variables are in memory
and they exists during the function call which means variables that got this location are temporary and after function execution finished, they won’t exist.
calldata
: Non-modifiable, non-persistent data location where function arguments are stored, behaves mostly like memory
data location and only available for external
functions.
Assignments between
storage
andmemory
(or fromcalldata
) always generate an independent copy.Assignments from
memory
tomemory
only create references. This means that changes to one memory variable are also visible in all other memory variables that refer to the same data.Assignments from
storage
to a local storage variable only assigns a reference.All other assignments to
storage
always creates independent copies. Examples for this case are assignments to state variables or to members of local variables of storage struct type, even if the local variable itself is just a reference.
Example: memory to memory
modifying
data
, also modifiedmeal
TLDR
use
calldata
when you only need read-only data, avoiding the cost of allocating memory or storage.use
memory
if you want your argument to be mutable.use
storage
if your argument will already exist in storage, to prevent copying something into storage over into memory unnecessarily.
Example
You can convert implicitly storage
to memory
and calldata
to memory
, but the reverse is not possible.
Other notes on reference:
Reference types don’t necessarily fit into 32bytes — 256 bits.
Amount of gas consumed during execution depends on data location. Creating independent copies from reference types are expensive thus it is recommended that mostly inside functions we should choose working with memory data location.
We must be careful in scenario when two or more different variables point same data location since any change in one variable will impact the others.
calldata vs memory
Calldata is almost the same as memory but you cannot manipulate (change) the variable. It's also more gas efficient.
When using (string
memory
name)
, a copy of the parameter is passed into delete holder[name]
, as per the function below:
However, using (string
calldata
name)
, the parameter would be passed directly into delete holder[name]
, without making a copy, thereby saving gas.
Since in the above function, the function parameter name is not modified within the scope of the function, we can opt to use calldata instead.
No point in making a fresh copy in a new memory location (which is what setting it to 'memory') does.
Use memory if you want to be able to manipulate the values and calldata when the parameter remain immutable.
One gotcha on this is that if you pass in a string (or bytes) from a different internal function where you had just created that string in memory, then you can't use calldata here. Example:
Non-modifiable, non-persistent data location where function arguments are stored,
Why is calldata cheaper?
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)
Additional reading
Last updated