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 {
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 {
struct User{
uint id;
uint balance;
}
mapping(uint => User) users;
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;
}
}`Preformatted text`
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;
}
}
I just changed memory to storage. Interesting looking above that others just simply removed any reference of memory or storage. I did however work through the problem like in the video before watching it. Kinda saw where we were going and so just gave it a shot.
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 {
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;
}
}
Thanks to all the commenters of the post for solving this problem. I often have problems with this, and I even opened this forum just because I was looking to solve it.
Hi @ekr990011,
Both solutions are correct and equally valid
What I would say, though, is that the one-line solution …
users[id].balance = balance;
… is shorter, more concise and, in this particular example, also clearer. However, sometimes using a local storage
variable as a pointer can be a useful intermediate step when performing more complex operations involving multiple properties and their values: it can help us to set our code out into separate logical steps, making it easier to read and understand.
Additionally, even though setting up the storage pointer with a local storage variable results in more code initially, the actual reference to the pointer ( user
) within the function body is shorter than referencing the “pointed-to-value” ( users[id]
) directly. So, if we needed to use the pointer multiple times within the same function body, then in this case we could ultimately end up with shorter code using the storage pointer and, probably more importantly, more readable code as well.
From tests that I’ve performed previously, it’s also interesting to note that both of the alternative solutions we are discussing consume more or less the same amount of gas. Using a storage pointer, and keeping 2 lines of code …
User storage user = users[id];
user.balance = balance;
… is only very very slightly more expensive than the more concise one line solution …
users[id].balance = balance;
With optimization turned on, the gas cost is exactly the same. Gas consumption, and therefore gas cost, is based on which low level operations (op codes) are performed by the EVM. My understanding is that the gas costs are the same for both of these alternative solutions because, even though the code is different, once compiled into bytecode, both are essentially performing exactly the same low level operations.
Let me know if anything is unclear, or if you have any questions
Hi @zacheryurueta,
Welcome to the forum! … I hope you’re enjoying the course
Yes … you’ll find lots of helpful information and support in these discussion topics. If you find yourself struggling with an assignment, but still want to try to solve it before seeing any solution code, you can always post a question here, and you may find the answer helps you to make more progress on your own
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 amount) public {
users[id].balance = amount;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
just changed “memory” to “storage” in the updateBalance fx and it worked for me.
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 {
User storage user = users[id];
user.balance = balance;
//User memory user = users[id];
//user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
It’s good that there will always be people like you who will write a solution to the problem and describe their actions. I appreciate it and am very glad to have responsive people on the internet. I’d have needed it two weeks ago when I lost all the data from my phone and had to contact https://www.salvagedata.com/memory-card-recovery/ to get everything back. Of course, these specialists returned all the files to me, but now I also know the purpose of the data location, thanks to you.
pragma solidity ^0.8.0;
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;
}
}
I took out the memory to at first see what error code i would recieve.
then i replaced memory with Storage and it worked just fine.
`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 @Xabier22
Even though the initial idea of this assignment is to update the existing balance by replacing it with the new one, I actually think that it does make more sense to do what you’ve done, and add an amount to the user’s existing balance using the addition assignment operator +=
(instead of the assignment operator =
).
However, if we add to, instead of replacing, the existing balance, I think the code looks clearer and more readable if we also change the name of the balance
parameter to amount
, because we are adding an amount to the balance (to give a new total balance), rather than replacing it with a new balance.
There is always more than one solution to these assignments, and alternative interpretations are equally valid.
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 {
User storage user = users[id];
user.balance = balance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
Problematic part :
function updateBalance(uint id, uint balance) public {
User memory user = users[id];
user.balance = balance;
}
With the above format, the variable user is stored in the memory, which means that after the function is done running, the variable will be erased.
When we can getBalance function, we check the balance of the mapping users.
But in the update function, we never update users…we only update a temporary variable that is deleted after the function is done running.
Some possible solutions :
- Here we directly update the balance for the specific (id) user
function updateBalance(uint id, uint balance) public {
users[id].balance = balance
}
- This is how to fix the current code without deleting any part of it (but it’s not a smart solution as the variable user is pointless)
function updateBalance(uint id, uint balance) public {
User memory user = users[id];
user.balance = balance;
users[id].balance = user.balance;
}
- (After watching solution video)
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
What I don’t understand with solution 3 though is :
How can this work ?
So yes, we successfully create a permanent variable (user) that stores the current data in users[id].
Then we update the balance of user (user.balance = balance). This is all fine, but where do we say that users[id].balance = user.balance ?
Because in the getBalance function we get the balance with users[id].balance, but after solution 3 is applied I don’t see where the new balance is stored in users[id].balance
We say user = users[id], but not users[id] = user. Can someone explain me ?