Data Location Assignment

I would either store the temp user variable back into the storage variable:

users[id].balance = user.balance;

or simply modify the storage variable directly:

users[id].balance = balance;

Edit:
From your solution, I realize that setting a storage variable equal to an existing storage variable actually sets the reference (address) of the two variables to be the same, thereby setting the original variable indirectly. That is interesting to know.
But I would still do it the way I stated! :wink:

1 Like
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; // Here is a one line change
    }

    function getBalance(uint id)  public view returns (uint) {
        return users[id].balance;
    }
}
1 Like

Nice solution @luiscal89 :ok_hand:

… and welcome to the forum! It’s good to see you here :smiley: I hope you’re enjoying the course so far!

Hi @Samm,

Nice analysis :ok_hand:

Both of your original alternative solutions are correct. The second one…

…would be preferable because:

  1. It uses less gas. This is because we don’t need to create a local copy of the User instance which is already stored in the mapping.
  2. It achieves in one line what the first alternative achieves in three i.e. it’s much more concise.

I agree with you there. In terms of gas, there isn’t much of a difference between the local storage variable option, and your more concise 2nd solution. That’s because beneath the syntax they are actually performing exactly the same low level operations. But I still think that your 2nd solution is neater, clearer and more concise. :slight_smile:

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;
    }
}
1 Like

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]; //changed from memory to storage
     user.balance = balance;
}

function getBalance(uint id) view public returns (uint) {
    return users[id].balance;
}

}

1 Like

My solution, if I understood properly the question…

pragma solidity >=0.7.5 <0.9.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;
    }

}
1 Like
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;
    }

}
1 Like
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 {
         //One solution is to change memory to storage 
         //This makes sure the variable is remembered after the function is finished running
         //User memory user = users[id];  <= old code
         User storage user = users[id];   // new code
         user.balance = balance;
    }

    function getBalance(uint id) view public returns (uint) {
        return users[id].balance;
    }

}
1 Like

Nice solution @Woland :ok_hand:
… and welcome to the forum! It’s good to see you here, and I hope you’re enjoying the course :slightly_smiling_face:

Nice solution @jeanphi :ok_hand:
… and welcome to the forum! It’s good to see you here, and I hope you’re enjoying the course :slightly_smiling_face:

Nice solution @Dustin_Gearhart :ok_hand:

You’re got the right idea, but it isn’t the variable that’s being remembered. By assigning users[id] to a local storage variable, we create a local “pointer” called user . This points to (references) the User instance in the mapping which is mapped to the id parameter input into the function. Any value assigned to this local “pointer” variable is effectively updating the instance stored persistently in the mapping.

The local variable user creates a temporary “bridge” to the mapping during execution of the function, so that the amount ( balance ) can be added to a specific user’s balance stored persistently in the mapping, before this “bridge” is lost when the function finishes executing.

Let me know if anything is unclear, or if you have any questions :slight_smile:

1 Like

I only changed the updateBalance method, to make sure that I not only update the user instance in the memory but in the storage.

function updateBalance(uint id, uint balance) public {
     User storage user = users[id];
     user.balance = balance;
}
1 Like

Quoted and added directly to my code as a comment :+1: Great explanation.

1 Like

Nice solution @Gabor_Gyorgy :ok_hand:
… and good to see you back here in the forum :slight_smile:

Solution for assignment:

pragma solidity 0.8.4;

contract Assigment {
    
    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 userToUpdate = users[_id];
         userToUpdate.balance = _balance;
    }

    function getBalance(uint id) view public returns (uint) {
        return users[id].balance;
    }
}
1 Like

Change updateBalance() - the data location of the “user” variable from memory to storage

from

function updateBalance(uint id, uint balance) public {
     User memory user = users[id];
     user.balance = balance;
}

to

function updateBalance(uint id, uint balance) public {
     User storage user = users[id];
     user.balance = balance;
}
1 Like
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 view {
         user storage _user = users[id];
         _user.balance == balance;
    } 
    function getBalance(uint id) public view returns(uint){
        return users[id].balance;
    }
}

Hi @alexdemc,
… and welcome to the forum! I hope you’re enjoying the course so far :slight_smile:

You have a couple of issues with your solution to this assignment. If you deploy your code, you will notice that when a user calls the updateBalance() function, their balance isn’t updated in the mapping. We know this because, if you then call getBalance() with the ID of the user who just tried to update their balance, the old balance is still returned.

These are the errors in your code — see if you can correct them so that your code works as it should:

This line of code is comparing two values, and not assigning a value to the user’s “record” in the mapping. This expression evaluates to true or false, but as the result isn’t saved or handled anywhere, this line of code has no effect, and so is redundant.

Because your code in the updateBalance() function body currently only reads the contract state, but doesn’t modify it, that’s why the compiler would have prompted you to make it a view function. However, when you correct the code so that the new balance is assigned to the mapping, your function will need to modify the contract state, and view will generate a compiler error.

One other observation…
You have started the struct and contract names with lower case letters. The convention is to start these with capital letters. This helps us to distinguish these from the names of functions, variables, mappings, parameters/arguments, and the data types string, uint, bool etc.
For example, by naming your struct user instead of User, it isn’t immediately clear that your mapping contains struct instances, or that your local _user storage variable creates a pointer to a specific struct instance in the mapping. Your code will still compile and work with the names you have used (all starting with lower case letters), but it makes your code less readable and less manageable for other Solidity developers, who are used to the naming conventions.

Let me know if anything is unclear, or if you have any questions about how to correct your code :slight_smile:

I didn’t mean to add a second equals, I fixed the errors I believe.

_user.balance == 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) public view returns(uint){
        return users[id].balance;
    }
}

The code now runs properly and the balance now updates.

1 Like