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

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

}

1 Like

My solution:

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

}

1 Like

Heey @jon_m, good to be back, it’s been a bit hard to study as much ever since I’ve gone back to the usual job, also I’ve been trying to get better at JavaScript before getting a bit deeper into Solidity, but for now, I seem to be understanding it pretty well. Thanks a lot for your comments they do help a lot. I did think that the first solution was a lot more straightforward and didn’t require the declaration of a new instance of the User struct, which as you mentioned would also need to be defined using the data location storage because it is created inside a function and its content would be lost after the function ends running, whereas the mapping users it’s stored with the storage data location by default because it was defined in the global scope of the contract.

Please do let me know if there’s something wrong with my understanding of it. Thanks a lot once again for your help :call_me_hand:

1 Like

Hey Ernest,

Yeh, it’s a real challenge combining study with a job!

You’ve been doing the right thing to concentrate on getting a solid understanding of JavaScript first, because that will really help with Solidity, as a lot of the coding concepts and syntax are similar — although, obviously there are some key differences.

That’s a really good explanation :muscle: and shows a good understanding of this assignment, and the concept of data location in general.

I’m glad you found the comments helpful :slight_smile:

1 Like

Awesome! Thanks a lot for the feedback! :muscle:

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 memory user = users[id];
         //user.balance = balance;
//SOLUTION HERE
         users[id].balance += balance;
    }

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

}
1 Like

Nice solution @Kippie :ok_hand:

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 do what you have done, and add an amount to the existing balance using the addition assignment operator += (instead of the assignment operator = ). However, I think your code would be clearer and more readable if you also change the name of the balance parameter to amount , because you are adding an amount to the balance, rather than replacing it with a new balance.

Let me know if you have any questions :slight_smile:

This is my solution:


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

Data Location Assignment

After having evaluated the difference between memory and storage, where memory is temporary and storage is persistent and can only be used with arrays, structs or mapping, I came to the conclusion that in the updateBalance function, the balance needs to be persistent to retain the current value after the function. The array within that function, users[id], needs to be persistent, therefore I changed memory to storage. In order to retain that balance and then add whatever amount afterwards, I just need to put the '+' sign next to equals in the user.balance assignment.
Hopefully this makes sense and was one of the correct answers. I am still new to coding in C++/Solidity, so always appreciate the feedback to improve.
Code below:

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]; //simply changed the user 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 {
     users[id].balance = balance;
}

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

}

1 Like

My Answer:

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 to storage
         user.balance = balance;
    }

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

}

1 Like

Nice solution @crypto-djent76 :ok_hand:

Correct … it needs to be saved in persistent storage so it isn’t lost when the function has finished executing.

Not really… All state variables (including mappings and structs) are saved in persistent storage, but we don’t need to declare them with the storage keyword, because this is the only data location they can have. Local string and array variables, and local variables defined as struct instances, are complex data types and so need to have their data location explicitly declared. Usually, this is memory , but in the case of struct instances (variables based on a predefined struct) we can also declare them with storage . Instead of a copy of the data, this creates a “pointer” (a reference) to a specific instance stored persistently in the contract state.

In your solution, users[id]  is not an array. It’s a reference to a specific User instance in the users mapping — the instance which has, as its key, the id parameter input into the updateBalance function. By assigning  users[id]  to a local storage variable, we create a local “pointer” called user. Any value assigned to this local “pointer” variable is effectively updating the instance users[id] stored persistently in the mapping (the instance referenced by the pointer).

In your solution…

… adding balance to user.balance in the second line, effectively adds the new balance value to the balance property of users[id] in the mapping…

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 do what you have done, and add an amount to the existing balance using the addition assignment operator += (instead of the assignment operator = ). However, I think your code would be clearer and more readable if you also change the name of the balance parameter to amount , because you are adding an amount to the balance, rather than replacing it with a new balance .

I hope you find these comments helpful. Let me know if anything is unclear, or if you have any questions :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 {
         User memory user = users[id]; //Is this line redundant as we can just users[id] directly?
         users[id].balance += balance; //directly used users[id].balance to have a += relationship with balance to top up a specific users balance
         //if just to update balance(alter and not addition), eliminate the + operator
    }

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

}

Might update later as I feel like i’ve missed out on something

1 Like

Hi Guys - Here’s my solution.

pragma solidity 0.8.1;
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 {
     //Change this "User memory user = users[id];" to the below line.
     users[id].balance = balance;
}

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

}

2 Likes

Hi @KK_Cheah,

Yes, it’s now completely redundant and can, therefore, be removed…
This first line defines a local variable user, but it’s no longer referenced in the second line. The compiler should have generated a yellow/orange warning for this. The warning message describes and confirms what the issue is and how to resolve it.

Your second line on its own provides all of the necessary functionality. As you say in your comments, it adds (+=) or assigns (=) the new balance value to the balance property of a specific User instance stored in the mapping ( users[id].balance ). The User instance to be updated, is specified by its key: the id value input into the function.

This is a good piece of analysis you’ve done here, laying out two valid options :ok_hand:
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 do what you have done, and add an amount to the existing balance using the addition assignment operator += (instead of the assignment operator = ). However, if you add to, instead of replacing, the existing balance, I think your code would be clearer and more readable if you also change the name of the balance parameter to amount , because you are adding an amount to the balance, rather than replacing it with a new balance.

Let me know if you have any further questions :slight_smile:

2 Likes

Nice solution @Davy2021 :ok_hand:
… and good to see you here in the forum! I hope you’re enjoying the course :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;
    }

}

In the original code it is saving the user’s new balance to the newly assigned user variable which is only stored in memory so we need to just save it to the original user mapping to fix the problem.

1 Like