When looking at sample contracts, sometimes arrays are declared in methods with "memory" and sometimes they aren't. What's the difference?
memory is a keyword used to store data for the execution of a contract. It holds functions argument data and is wiped after execution. storage can be seen as the default solidity data storage. It holds data persistently and consumes more gas.
Memory: This is local memory available to every function within a contract. This is short lived and fleeting memory that gets torn down when the function completes its execution. Calldata: This is where all incoming function execution data, including function arguments, is stored.
The first is “storage”, where all the contract state variables reside. Every contract has its own storage and it is persistent between function calls and quite expensive to use. The second is “memory”, this is used to hold temporary values. It is erased between (external) function calls and is cheaper to use.
Solidity is an object-oriented programming language created specifically by the Ethereum Network team for constructing and designing smart contracts on Blockchain platforms. It's used to create smart contracts that implement business logic and generate a chain of transaction records in the blockchain system.
Without the memory keyword, Solidity tries to declare variables in storage.
Lead Solidity dev chriseth: “You can think of storage as a large array that has a virtual structure… a structure you cannot change at runtime - it is determined by the state variables in your contract”.
That is, the structure of storage is set in stone at the time of contract creation based on your contract-level variable declarations and cannot be changed by future method calls. BUT -- the contents of that storage can be changed with sendTransaction calls. Such calls change “state” which is why contract-level variables are called “state variables”. So a variable uint8 storagevar; declared at the contract level can be changed to any valid value of uint8 (0-255) but that “slot” for a value of type uint8 will always be there.
If you declare variables in functions without the memory keyword, then solidity will try to use the storage structure, which currently compiles, but can produce unexpected results. memory tells solidity to create a chunk of space for the variable at method runtime, guaranteeing its size and structure for future use in that method.
memory cannot be used at the contract level. Only in methods.
See the the entry "What is the memory keyword? What does it do?" in the FAQ. I quote it here:
The Ethereum Virtual Machine has three areas where it can store items.
The first is “storage”, where all the contract state variables reside. Every contract has its own storage and it is persistent between function calls and quite expensive to use.
The second is “memory”, this is used to hold temporary values. It is erased between (external) function calls and is cheaper to use.
The third one is the stack, which is used to hold small local variables. It is almost free to use, but can only hold a limited amount of values.
For almost all types, you cannot specify where they should be stored, because they are copied everytime they are used.
The types where the so-called storage location is important are structs and arrays. If you e.g. pass such variables in function calls, their data is not copied if it can stay in memory or stay in storage. This means that you can modify their content in the called function and these modifications will still be visible in the caller.
There are defaults for the storage location depending on which type of variable it concerns:
Storage holds data between function calls. It is like a computer hard drive. State variables are storage data. These state variables reside in the smart contract data section on the blockchain.
Memory is a temporary place to store data, like RAM. Function args and local variables in functions are memory data. Ethereum virtual machine has limited space for memory so values stored here are erased between function calls.
Let's say we want to modify the top-level state variable inside a function.
// state variables are placed in Storage // I am gonna mutate this inside the function int[] public numbers function Numbers()public{ numbers.push(5) numbers.push(10) int[] storage myArray=numbers // numbers[0] will also be changed to 1 myArray[0]=1 //Imagine you have an NFT contract and store the user's purchased nfts in a state variable on top-level // now inside a function maybe you need to delete one of the NFT's, since user sold it // so you will be modifying that list, inside a function using "storage" }
int[] storage myArray=numbers
in this case myArray will point to the same address as "numbers" (it is similar to how referencing objects behave in javascript). In the function I added 5, then 10 to "numbers" which is placed into Storage. But if you deploy the code on remix and get numbers[0]
, you will get 1 because of myArray[0]=1
myArray
as memory it will be a different story.// state variables are placed in Storage int[] public numbers function Numbers() public{ numbers.push(5) numbers.push(10) // we are telling Solidity make numbers local variable using "memory" // That reduces gas cost of your contract int[] memory myArray=numbers myArray[0]=1 // Now, this time maybe you want to user's NFT's where price is less than 100 $ // so you create an array stored in "memory" INSIDE the function // You loop through user's Nft's and push the ones that price<100 // then return the memory variable // so, after you return the memory variable, it will be deleted from the memory }
In this case, "numbers" array is copied into Memory, and myArray now references a memory address which is different from the "numbers" address. If you deploy this code and reach numbers[0]
you will get 5.
I showed the difference on a simple function so it can be easily tested on Remix
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With