It is written in many places how these things are. But what not easy to decide when to use which of them, as it needs a deeper understanding to choose.
So I want to note the quick heuristic methods to choose these.
Public vs. External
TL;DR;
So if you know the function you create only allows for external calls, go for
external
. It provides performance benefits and you will save on gas.
Basically, public
means it can be external
or internal
, the compiler need additional work for the public function. With the external
only, it allows arguments to be read directly from calldata
, saving the copying step.
Easy read here:
- https://gus-tavo-guim.medium.com/public-vs-external-functions-in-solidity-b46bcf0ba3ac
- https://ethereum.stackexchange.com/a/19391/76945
Memory vs. Calldata vs. Storage
TL;DR;
- 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.
Ref:
To research more
I am still not sure why most of the OpenZeppelin libs choose to use memory
over calldata
, although they don't mutate them. For example: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol#L179
Top comments (1)
Found this one on why OpenZeppelin team uses
memory
overcalldata
.forum.openzeppelin.com/t/why-does-...
It seems
calldata
is limited in functionalities when using withinternal
function, so they go formemory
.