Data Location Assignment

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 {
     users[id].balance= balance;
}

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

}

2 Likes

Hi @Randallcrum,

Don’t change your thinking! Looking to understand the context of the problem and why different solutions work is an important skill to develop as well, and will help you to “join the dots” that much quicker and efficiently. And rewriting the code more efficiently (as long as it still achieves the same objective) is always desirable.

However, a good approach is to first solve the immediate problem, then, once you’ve checked the solution, then start to analyse how the solution works and consider the wider context, and if there are other alternative solutions.

In fact, the code given to you in this assignment can be improved in several ways. Some students have come up with some good suggestions, and which you’ll find posted here in this discussion thread… if you hunt around hard enough :wink:

Nice solution @decrypter :ok_hand:
… and welcome to the forum! It’s great to see you here, and I hope you’re enjoying this course :smiley:

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 memory user = users[id];
         users[id] = User(id, balance);
    }

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

}


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

1 Like

Hi @Andrewg,

In the first line you define a local variable user, but then you don’t reference it in the second line. So the first line is completely redundant and can, therefore, be removed. This leaves us with your second line, which clearly shows that your updateBalance function actually just does exactly the same thing as the addUser function:

function addUser(uint id, uint balance) public {
    users[id] = User(id, balance);
}

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

If we have two functions that perform exactly the same operation, that’s not efficient, and so in this case we might as well remove one of the functions and just call the remaining one something more general, such as update().

However, this is hardly ideal. So what you want to aim for with the updateBalance function, is code that only updates the balance property for a particular user ID, and not the whole User instance. We only need to create a whole new User instance when we add a new user, because once added, their user ID won’t need to change (at least not at the same time as their balance).

Thanks, yes I see it now

1 Like

pragma solidity 0.8.3;
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;
}

}

2 Likes

Nice solution @Jab_kaiju :ok_hand:
… and welcome to the forum! :smiley:

It’s great to see you here, and I hope you’re enjoy the course!

In the updateBalance function I changed it so it selects the users array member at location [id] and updates its 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;
    }

}
2 Likes
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 {
         users[id].balance = balance;
    }

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

}
2 Likes

Nice solution @Bryan :ok_hand:

Just one point…

users is a mapping (not an array).
Data stored in a mapping is selected using a key (in this case id ).
Data stored in an array is selected using an array index.

Thanks for the clarification Jon, it is a mapping not an array.

1 Like

I modified the updateBalance function from:

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

to:

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

The issue was related to the usage of a memory variable (which is temporal) to store persistant data (which is of type storage). When you assign a storage variable to a memory variable, the assignation is done by value instead of by reference. This means that there is no relationship between both variables, so, if you modify one, the other won’t be changed (actually, data is stored in different places, so it is easier to figure it out).
I actually made the changes in Remix, deployed the contract and tested my fix, leading to the following result:
image

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

    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;
         // or instead of the 2 lines above just do:
         // 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;
    }

}

By changing user memory to user storage in the UpdateBalance function now this points to the user in the mapping. This refers to the mapping value in storage not in memory.

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