Hi @donodina,
Good to see you back here in the forum
In case you haven’t, make sure you also read the comments on this post, so you get the full explanation.
Just let me know if you have any questions.
Hi @donodina,
Good to see you back here in the forum
In case you haven’t, make sure you also read the comments on this post, so you get the full explanation.
Just let me know if you have any questions.
Nice solution @codingluan
Your explanation is also very good. Just one comment …
The temporary copy of the User
instance with the new balance is only stored until the function finishes executing, when it is lost.
The function finishes executing and the copy is gone. Such a valuable comment. Thank you, @jon_m!
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
users[id].balance = balance; // modify actual user, not a copy
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
memory was changed to storage.
Memory is used to store temporary data-- when the function is done, it is no longer stored.
Storage refers to permanent storage of data that is persistent over function execution.
This is my solution: memory changed to storage to ensure the data is saved persistenatly and not temporarily (what was causing the previous error)
pragma solidity 0.7.5;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
Nice solution @DarthKimie
Correct … and when we define the data location of a local variable as storage
, this creates a storage pointer. This only points to (references) the value already saved in persistent storage which is assigned to it (in our case users[id]
); it doesn’t create or store a separate copy of it. It’s like a temporary “bridge” during execution of the function to wherever in the contract state it points to (in our case a specific struct instance in the mapping).
… I think you mean “persistent after function execution” i.e. the data isn’t lost when the function has finished executing (because it has been assigned to a specific struct instance in the mapping).
Also, for your next assignments, please don’t post screen shots, because we can’t copy and paste your code in order to execute and test it, if we need to. Instead, follow the instructions in this FAQ: How to post code in the forum
Let me know if you have any questions
pragma solidity 0.7.5;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
Switch keyword memory to storage. So the problem was that memory was only saving user balance while the function ran ,so anything happening after was not getting saved. Replacing memory with storage allows the user balance data to persist over time and function executions.
pragma solidity 0.7.5;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
pragma solidity 0.7.5;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
pragma solidity 0.7.5;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
User storage user = users[id]; // replace memory to storage
user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
pragma solidity 0.7.5;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
Nice solution @Renz
… and it’s good to see you back here in the forum! I hope you’re enjoying the course
On the whole, your explanation is good. Here are some additional comments …
It was a temporary copy of the whole User
struct instance (stored in the mapping) which was first stored in memory …
User memory user = users[id];
Then, the new balance was assigned to the balance property of this temporary copy, where it was only saved until the function had finished executing, at which point it was lost …
user.balance = balance;
Yes … and it’s interesting to understand how this actually happens …
When we define the data location of a local variable as storage
, this creates a storage pointer. This only points to (references) the value already saved in persistent storage which is assigned to it (in our case users[id]
); it doesn’t create or store a separate copy of this value, as it would if we defined the data location as memory
. A storage pointer is like a temporary “bridge” during execution of the function to wherever in the contract state it points to (in our case a specific User
struct instance in the mapping).
Any value which is then assigned to a property of the local “pointer” ( user
) will effectively update that same property of the specific User
instance in the mapping which is referenced by the pointer. This enables a specific user’s balance (stored persistently in the mapping) to be reassigned with the new balance
(input into the function), before our “bridge” disappears when the function finishes executing…
user.balance = balance;
Just let me know if you have any questions.
pragma solidity 0.7.5;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint _balance) public {
users[id] = User(id,_balance);
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.7;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
pragma solidity 0.7.5;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
pragma solidity 0.8.7;
contract MemoryAndStorage {
mapping(uint => User) users;
struct User{
uint id;
uint balance;
}
function addUser(uint id, uint balance) public {
users[id] = User(id, balance);
}
function updateBalance(uint id, uint balance) public {
users[id] = User(id, balance);
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
Hi @thanasornsawan,
Your solution has, effectively, made the updateBalance function exactly the same as the addUser function.
While this does still work…
I assume you’ve already seen the 2 alternative solutions suggested in the follow-up video. Can you see how they are more suitable?
You may also find this related discussion interesting, which starts in the post I’ve linked to and continues over several more.
Just let me know if you have any questions