Data Location Assignment

Nice solution @R0bert :ok_hand:

… and good to see you back here in the forum! … I hope you’re enjoying the course :slightly_smiling_face:

1 Like

Was afraid this would take me the whole day, just tried to change ‘memory’ to ‘storage’ (so it’s stored permanently) and it worked! :grin:

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

Turns out I was WAYY over thinking this at first.

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;

}

}

2 Likes

Great being back! Finally some time to get back to coding ! :grinning:

2 Likes

Hello:D

This took me longer than expected. Got the right answer in the first 15min but struggled to compile, deploy and trigger the right contract in remix :smiley: I noted that today haha what a fail guys :see_no_evil:

Anyway, finally I got it.

Since we are just asked to update the balance, I didn’t add the incoming balance to the existing one also I would do that in a diffrent function called addFunds or something like this :smiley:

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.11;

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;
    }
}
2 Likes
// SPDX-License-Identifier: undefine
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 memory user = users[id];
         user.balance = balance; // change balance
         // user.balance += balance; // increment balance
         users[id]=user;
    }

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

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

}

Nice solution @Bensen :ok_hand:

:raised_hands:

Good point :+1:

In fact, 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 makes more sense to add an amount to the user’s existing balance instead. So, I would still just have the one updateBalance() function — changing its name to addFunds() if you want — and replace the assignment operator=  in the second line of code …

… with an addition assignment operator+=

user.balance += balance;

In addition, if we add to, instead of replacing, the existing balance, I think the code will look 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, rather than replacing it with a new balance

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

There is always more than one solution to these assignments, and alternative interpretations are equally valid and to be encouraged. You can always add comments to your code to explain anything you’ve done a bit differently or are unsure about :slight_smile:

Just let me know if you have any questions.

Nice alternative solutions, @LELUK911 :ok_hand:

Even though you probably realised that the initial idea of this assignment is to update the existing balance by replacing it with the new one (your main solution), I actually think that it makes more sense to do what you’ve shown in your in-line comment as an alternative, 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 will look 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 the new total balance.

Just let me know if you have any questions :slightly_smiling_face:

1 Like

Hi @imran82,

Your solution won’t compile and you should have got a red compiler error for this line …

This is because you are trying to assign the new balance to the balance property of an undefined user variable. You either need to first define user in a line of code above, or directly reference the User instance (the user’s record) in the mapping and assign the new balance to that.

Have a go at correcting this. Let me know if you have any questions, or if you need any more help :slight_smile:

1 Like

i am not able to compile because new remix version doesnt let me to compile with older version

Try activating Auto Compile (mark the Auto Compile box under Compiler Configuration in the Solidity Compiler panel in Remix).

Remix should then automatically select the correct compiler version (0.7.5) in the Compiler field at the top of the Solidity Compiler panel. If it doesn’t, then you can manually select it from the dropdown.

If, for some reason, you only have one compiler version available to you in this dropdown (e.g. the latest, 0.8.11) then just change your contract’s pragma statement to this same version.

You need to be able to compile your contracts, otherwise you won’t identify any errors. You also won’t be able to deploy your contracts if they haven’t been compiled.

If you can only compile with the latest version (v0.8), you can still do the course with this version instead of v.0.7.5 (used in the videos). There is only one syntax change in v.0.8 that affects this course, which I can explain to you if necessary. Just let me know.

Thanks for help. Now remix id is working properly. It was giving error as i was using struct instead of mapping. Now i have updated it
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}

Thanks for pointing it out. I hope you will help me out in future also.

2 Likes

so my original explanation was wrong. :sweat_smile:
but my code was right so yay?!

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

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

         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];  // use storage instead of memory for referen to location of storage user 
     user.balance = balance;
}

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

}

2 Likes

In the updateBalance function, store the User data in storage instead of memory. Data stored in memory will not persist after their function scope finishes. Data stored in storage will persist after the function finishes executing.

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

Hey @imran82,

Glad you resolved this in the end :slightly_smiling_face:

Nice solution @DeMarco_Saunders :ok_hand:

… and welcome to the forum! I hope you’ve been enjoying the course :slightly_smiling_face:

What was your original explanation? … and do you now understand how the solution you’ve chosen (with the local storage variable) works? You’ll find a full explanation in this post.

Just let me know if you have any questions.

Nice solution @fooku :ok_hand:

… and welcome to the forum! I hope you’ve been enjoying the course :slight_smile:

You definitely have the right idea here :+1:

When we define the data location of a local variable as storage , this creates a storage pointer . This references the value already saved in persistent storage which is assigned to it: in our case users[id]

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.