Now we have new tools to study in more detail the difference between values in memory and values in storage. Let’s take the opportunity and write a contract that uses some of the types we’ve already studied.
Let’s start by creating a structure to store information about a monster game character.
struct Monster {
string name;
uint8 force;
}
Game participants, who are network accounts, can own a monster. The best data structure to store such information is mapping.
mapping(address => Monster) public monsters;
As the variable monsters is public, we don’t need to explicitly write a function to retrieve the monster owned by a given address. Thank you, Solidity.
Let’s start by writing a function to create a new monster. It will belong to the account that initiated the transaction and will have a strength of only 1.
function createMonster(string calldata _name) public {
monsters[msg.sender] = Monster(_name, 1);
}
Now let’s write a function to change the monster’s strength. The simplest way is to change the value directly in storage, as in the function below.
function changeForceStorage(address _address, uint8 _newForce) public {
Monster storage monster = monsters[_address];
monster.force = _newForce;
}
The variable monster declared inside the function is a pointer to a value in storage. It does not create a new variable in storage, because it is not possible to create new variables in storage on the fly. All state variables are created at deploy time.
As it is a pointer, it is not possible to assign a monster directly to it. The following code would not be allowed.
Monster storage monster = monsters[_address];
monster = Monster("Paul",3);
It is not possible to replace a pointer with a monster, but we can use the pointer to change a field of the variable that is a monster, as we did in the line below.
monster.force = _newForce;
Another way to change monster strength would be to create a new monster in memory and replace it in storage at some point.
Monster memory monster = monsters[_address];
monster.force = _newForce;
monsters[_address] = monster;
This second way is more costly in terms of gas, as it creates an object in memory before storing it in storage. However, it is possible that the contract wants to do other operations with this object before storing it permanently in storage, so this would be the ideal method.
Reference types between memory and storage
Reference-type values are those that hold a pointer to where the value is actually stored. The array is a reference type value. Let’s see this in the code below.
function memoryToMemory() public pure returns (uint) {
uint[3] memory array1 = [uint(1),2,3];
uint[3] memory array2 = array1;
array1[0] = 4;
return(array2[0]);
}
We have two arrays, both in memory. First we create the variable array1, containing 3 elements, [1,2,3]. When we declare array2 to be array1, array2 receives the same pointer as array1. This means that the value, [1,2,3], is the same for both variables, array1 and array2.
When changing a value of array1, the same value is changed for array2, because they both point to the same place in memory. This is typical behavior for reference-type variables.
Let’s now do something similar, but completely different. Let’s see the code below.
uint[3] array1 = [uint(1),2,3];
function storageToMemory() public view returns (uint, uint) {
uint[3] memory array2 = array1;
array2[0] = 4;
return(array1[0], array2[0]);
}
// return: 1, 4
Again, we have two arrays. But now array1 is in storage, while array2 is in memory. When array2 receives array1, it now receives a copy of array1 and no longer its pointer.
This is because storage and memory are different storage locations. Variables cannot share the same object because each object needs to be in its storage location: one in memory and one in storage.
When mixing memory with storage, you have to be a little careful with reference-type variables. However, a little reflection will show that the above behavior is as natural as possible.
Thanks for reading!
Comments and suggestions about this article are welcome.
Any contribution is welcome. www.buymeacoffee.com/jpmorais
Join Coinmonks Telegram Channel and Youtube Channel get daily Crypto News
Also, Read
- Copy Trading | Crypto Tax Software
- Grid Trading | Crypto Hardware Wallet
- Crypto Telegram Signals | Crypto Trading Bot
- Best Crypto Exchange | Best Crypto Exchange in India
- Best Crypto APIs for Developers
Learn Solidity lesson 16. Memory and Storage revisited. was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.