Data Location Assignment

Hi @donodina,

Good to see you back here in the forum :slight_smile:

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 :ok_hand:

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.

1 Like

The function finishes executing and the copy is gone. Such a valuable comment. Thank you, @jon_m!

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;  // modify actual user, not a copy
}

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

}

2 Likes

Screenshot 2021-12-30 210129

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.

3 Likes

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

}
1 Like

Nice solution @Placebo :ok_hand:
… and it’s good to see you back here in the forum :slightly_smiling_face:

Nice solution @DarthKimie :ok_hand:

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 :slight_smile:

1 Like

Thank you @jon_m , I appreciate the clarification.

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

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

}
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 {
         User storage user = users[id]; // replace memory to storage
         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 {
         User storage user = users[id];
         user.balance = balance;
    }

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

}
1 Like

Nice solution @Renz :ok_hand:

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

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;

    }

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

}

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

}
1 Like

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 :slight_smile:

1 Like