Data Location Assignment [OLD]

Hi @Carlosvh96,

Do let us know if there is anything you still don’t understand and we’ll do our best to explain it in a way that helps you :slight_smile: You’re doing the right thing by trying to practise more, as some of these concepts only “click” after working through some more examples. You’ll come across lots more examples as the course progresses, so don’t worry if there are still a few loose ends, as you’ll find these get tied up later on. But do let us know if there is anything major you are struggling with.

That’s right. It’s redundant because we don’t do anything with the new balance stored only temporarily as a property of the local user variable.

This is the original code that you had to change, so there is no repetition here, it’s just incorrect and, as you say, redundant…pointless. We could just replace memory with storage, and that would solve the problem, but this would be less concise, and perhaps this is what you mean.

That’s absolutely correct. The version you chose does exactly that :ok_hand:

1 Like

Hi @RojasMessilia and @niore,

This alternative solution is correct, but is very long-winded, repetitve and not very concise. It also consumes more gas and so will be more expensive than the following solution…

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

As you can see this alternative is also more concise. I like @Carlosvh96’s comment about this solution…

Hi @niore,

This is incorrect, I think you may have meant…

 users[id].balance = balance;
// users[id].balance instead of balance[id].balance

This would be correct, because the mapping name is users.

2 Likes

Excellent analysis and edit @tnc :muscle:

… is definitely more concise (which is why I prefer it, by the way). Perhaps that’s a better way of describing it than…

… because they both consume about the same amount of gas.

1 Like

Nice solution and analysis @Paul_Mun :ok_hand:

Just a couple of observations…

What you are changing here isn’t the data type but the data location.
Data types are uint, int, bool, string etc. The actual data type here is User (a struct instance).

The specific user is an instance of the User struct, yes, but it’s stored in the mapping, and so it’s the mapping we need to access and update, not the struct.

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

Just a couple of comments about the terminology:

This is a local variable, with the name user, and stored temporarily in memory (its data location). It isn’t a modifier.

1 Like

Nice solution @Andro :ok_hand:

Yes, I totally agree! So, well done for persevering! :muscle:

… don’t you mean after the updateBalance function is executed? The addUser function updates the mapping (with the new User instance) directly, and doesn’t declare a local variable to store data temporarily in memory. It’s the updateBalance function which initially did that.

1 Like

Good points!
Now that I now that the when you set a variable you get a pointer and not a copy it makes sense that is not most efficient.

Ahh ok I see what you mean, that makes complete sense! Thank you for the clarification on this.

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

}

or

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

Thanks for answering. Yes, that’s exactly what I meant, I must have copied the wrong function name.

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

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

}

1 Like

Hi @tnc,

You only create a pointer to a value (instead of a copy of that value) when you assign a value stored in storage (in a state variable) to a local variable declared with storage. Creating a pointer consumes less gas than creating a copy. You create a temporary copy of a value stored in storage when you assign it to a local variable declared with memory, and this consumes more gas.

//That's why...
User storage user = users[id];
user.balance = balance;
// actually consumes about the same amount of gas as
users[id].balance = balance;
1 Like

Updated the User local variable data storage location from memory to storage to ensure that values were being updated in the same location and would persist after the updateBalance function had been executed.

User memory user = user[id] >>>> User storage user = user[id]

1 Like

Change memory to storage so you can add on to the contract over time. If it is uses memory it is like everything starts fresh every time the contract is used.

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

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

In the updateBalance function you need to change the users[id].balance = balance; to
User storage user = users[id];
user.balance = balance;
Memory is a temporary place to store data whereas Storage holds data between function calls.

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

The updateBalance() function was loading the User into the memory and updated the balance in this memory version of the object, but never persisted it back into storage. I went for the easiest way and updated the balance straight into the mapping in Storage without the need to load it into memory 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 {
         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;
    }

}

In this code above I adjusted the “user” object to store its data within the Storage and not within the Memory, as the memory is temporary and the information is lost once the function exists.

1 Like