Memory v calldata

Memory

Used for storing variables that are only needed temporarily during the execution of a function, and cannot be accessed outside the function.

  • can be used for both declaring function parameters and within function logic

  • mutable (variable values are modifiable)

  • non-persistent (the value does not persist after the transaction has completed)

Calldata

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

  • used to hold function arguments passed in from an external caller; user or another contract.

  • immutable: calldata is read-only and cannot be modified by the function.

  • calldata is cheaper than memory.

memory vs calldata

function doSome(bytes calldata data) external {}    // uses less gas

function doSome(bytes memory data) external {}
  • By declaring calldata, you can avoid the overhead of copying data into memory and reduce the amount of gas needed to execute the function. [CALLDATALOAD]

  • memory is more expensive than calldata. Because, it will copy the data from calldata into local memory, as an additional step. [CALLDATACOPY]

Why bother using memory then?

  • We cannot modify calldata; read-only

  • If you need to modify function arguments that are stored in calldata, you must first copy them into memory.

  • So in this scenario, we are better served declaring myBytes as memory

Alternatively

  • memory can be cheaper than calldata if you need to do modifications to the external data passed to the function.

  • use calldata when you are not going to modify the value of the variable passed as calldata inside the function.

circle-info

If you only need to read the data, you can save some gas by storing it in calldata.

More on calldata

  • calldata is where data from external calls to functions are stored.

  • calldata contains parameters of a function as allocated by the external caller

  • msg.data of an external call is held in calldata

  • A byte of calldata costs either 4 gas (if it is zero) or 16 gas (if it is any other value).

circle-info

In external calls to functions (when passing parameter string), opt to use calldata string, instead of memory string.

Gotcha!

One gotcha on this is that if you pass in a string (or bytes) from an internal function, where you had just created that string in memory, then you can't use calldata here.

Example

  • when execution moves from line 4 to 5, it is not an external call. There is no msg.data that holds calldata to be passed into callFunction

  • so in the absence of msg.data, there is no calldata that can be accessed.

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.

EXCEPTION: Layer-2

  • In the context of a rollups/layer-2, calldata goes from the cheapest resource to the most-expensive resource.

Last updated