Data Location Assignment

HELL YEA!!! I guess that was one of the solutions!!! EEEFFFFF YEAAAA
DDDDUUUUUUKKKKKKKAAAA!!!

Im going to be honest. I have absolutely no idea how to update the balance. So i just cheated and switched memory to storage in the line after my “updateBalance” function.
Im sorry man i really need to see what the solutions were cause all i did was basically make
my updateBalance function work like my addUser function. -__-. I looked over the videos again to relearn memory and storage and i couldnt figure it out. All i know is that memory doesnt work outside the function after its completed. Duuka… :*( I will do my best to learn from this failure, however its time to move on after 4hrs of trying to figure this out lol.

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

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

or

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

I dont know if for some reason we need the object “User”, but i guess we can just change the array directly. If we need the object for some reason, we can just point the array content on index to the created object.

1 Like

Ok, so it looks like the error is occuring because we are updating the variable “user” in memory but not the User instance inside the users mapping.

Here’s my solution:

function updateBalance(uint id, uint balance) public {
         users[id].balance = balance; 
         // Instead of copying the user to memory, we can update the user directly in storage
    }
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;
    }

}

Correction: Replace ‘memory’ with ‘storage’ in updateBalance.

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

The quickest method to fix the updateBalance function would be to replace User memory user = user[id]; to User storage user = user[id]; I don’t know if this is the most efficient solution as by replacing memory with storage would make it so that the information is permanently stored within the contract before it goes to update the users balance.

My only question would be that if we were to do this, wouldn’t every update to the balance be stored in the contract needlessly wasting space?

1 Like

All I did was change memory to storage.

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

}
  • Changed memory to storage in the updateBalance function, changing storage location from memory to storage will not create a new copy of data, rather it will create a pointer to storage. Hence any change in user object will be reflected in the storage itself.
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 ; // - answer 
    }

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

}
1 Like

Hi @jon_m. It took me a long time to make a reply on this comment of yours for honestly I didn’t understand it the first time. I’m very new to programming (only 3 months) so I needed to read a lot of documentations about solidity (the many words and its meaning). And it just made me realize I still really need to read more and practice what I read. Lol

Anyways, reading it again now, I felt like I need to say thank you for your explanation. It surely shed some light to my confuse mind. Thank you so much!

If there’s anything you can suggest that I read to fast track my learning that would be very much appreciated.

1 Like

Hi @gkassaras,

Valid points :+1:

I did actually look at the gas cost differences a while back, and changing memory to storage (and keeping 2 lines of code) was only very very slightly more expensive than the more concise one line  contractUsers[id].userBalance = newBalance; However, as you predict, the gas cost is exactly the same with optimization, which makes sense as both versions are essentially performing exactly the same operations. So, I think it’s more down to personal style, and also, as you say, which one allows easier debugging, code auditing and so, ultimately, more security. And having had a look at your profile, I can see you’ve had many years of experience in program security, security testing, security assurance and risk assessment. So thank you very much for your input, comments and well-reasoned opinion about the alternative solutions to this exercise from a security and assurance point of view — it makes for a more interesting and thought-provoking discussion.

If we change the functionality of the addBalance function to add an amount to a user’s existing balance (instead of replacing it with a newBalance), do you not think that it would be clearer to rename the function deposit (or similar) and rename the parameter newBalance => amount (or similar)? We are adding an amount to an exisiting userBalance to create a newBalance, rather than adding the newBalance to the exisiting userBalance. Obviously, the assignment operator = or += makes it clear whether we are adding or reassigning, but don’t you think that this is also better reflected in the names we choose as well?

Nice solution, and great question @Stequal :ok_hand:

This line isn’t making a copy or saving any new data in persistent storage. Instead, it creates a pointer (a reference) to a specific User instance in the users mapping — the one which has the id parameter input into the function as its key). This means that when balance is assigned to user.balance in the second line it is effectively being assigned to users[id] in the mapping. This means the update is made to persistent storage, instead of just being saved temporarily in memory within the function until the function finishes executing.

So, no — this code doesn’t save every updated balance as separate values within persistent storage. Instead, each time the balance is updated, the exisiting balance is overwritten with the new one (the value is reassigned).

In terms of comparing the efficiency of different alternative solutions, have a look at the following 3-post discussion, which I think will get you thinking about the different factors that need to be considered:
https://forum.ivanontech.com/t/data-location-assignment/27990/17?u=jon_m
https://forum.ivanontech.com/t/data-location-assignment/27990/20?u=jon_m (reply to previous post)
https://forum.ivanontech.com/t/data-location-assignment/27990/31?u=jon_m (reply to previous post)

Let us know if this answers your question, and if it gives you a better understanding of what the code is actually doing :slight_smile:

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

Hey @zai,

Don’t worry about not replying straight away! I know that sometimes we first need to take some time to think things through. Also that’s normal to not understand everything when someone explains things to you for the first time. You shouldn’t let that slow you down too much, because, as long as you read things over a few times and try to understand as much as possible, then you will find that the more difficult concepts do eventually make a lot more sense later on. I sent you some quite detailed comments because you had put a lot of effort into attempting to explain what the code was actually doing in this assignment solution. This is a great way to learn, because even if your explanation isn’t quite right to start with, the main thing is you are getting your brain used to thinking about things in a certain way. It also makes it easier for someone else to see what it is that you understand, and the things you need more help with.

In terms of additional reading material it can be difficult at first because a lot of the documentation, information, and articles about Solidity can be quite confusing for beginners — especially because of all the new terminology. That’s one of the reasons why I really recommend that, after completing an assignment and posting your solution, take some time to study some of the other student posts in the same thread, and try to understand the solutions that may be different to yours. There are often several possible alternatives. You will also learn a lot by reading through some of the comments and feedback posted here. Some may not make sense, but some will provide you with useful additional information, get you thinking a bit more deeply about what you’ve just learnt, and it’s also a good way to start getting used to reading about code, understanding the terminology, and also to practise reading and understanding the code itself. You should also have a look at the general discussion thread that comes with each section of the course. You will find lots more useful information and comments here, and it’s also good to see the sorts of questions other students are asking. Another good way to learn is to start posting your own questions, and when you get more confident, if you know the answer to someone else’s question, try answering that as well.

Another good piece of advice is not to rush too quickly through the courses. Take your time, spend time doing your own research, and experiment with the lecture and assignment code in Remix by reworking it, adapting it, and extending it.

Apart from that, just doing a search using keywords about something you want to understand better will often give you links to Question & Answer Knowledge Sharing Sites such as Ethereum Stack Exchange or Stack Overflow, which can be difficult at first, but once you get used to scanning and finding information that makes sense to you, this can be an invaluable source of information and example code. When searching, you’ll also often find Medium articles in the search results. Some of these can be really good, but just be aware of when they were written (see below about older/newer versions of Solidity)

The other thing I really recommend is finding some good YouTube channels about Solidity. A very good one that I use a lot for reference is:
https://www.youtube.com/c/EatTheBlocks
Have a hunt and find some beginner tutorials first to see how useful and helpful you find them. I often look for this channel’s videos when I’m doing a search about something I would like to find out more about. You need to be careful about the version of Solidity used in each video though, as many of the beginner ones will use older versions. This isn’t a major problem if you are just using them for a general introduction and extra information for different concepts, but you need to be aware of it. You can then check with more detailed documentation to see if later versions have implemented any changes. This channel also has some good videos summarising the main changes that have been implemented with new versions.

Finally, the most comprehensive documentation for Solidity is:
https://docs.soliditylang.org/en/v0.7.5/index.html
This is a link to the documentation for version 0.7.5, the version you are using in this course.

I think that’s enough information for the time being! :muscle:
I hope you find it helpful and inspiring! :grin:

1 Like

@jon_m Thank you really for taking some time answering my request! I usually have information overload when I search the net about solidity and it’s exhausting most of the time. I’ll just take one step at a time.
Yes, I totally agree that it really helps reading the answers of others. Hopefully, time will come that I wont be just reading answers but will start giving them soon and help out.
Will definitely check out the links that you provided. Thank you so much again!

1 Like

I got the point but I have difficult in writing the code. The codemap is the following:
1 – User ID and balance are saved in the storage
2 – Amount to send or to change is saved in the memory
3 – New balance is calculated and saved in the memory
4 – New balance will replace balance and saved in the storage
Is anything wrong in my mental map?

1 Like

In the original code, the problem is that we are creating a memory variable, and modifying it, so it will be deleted once the updating function is finished.

We have to use “storage” instead:

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

Another solution would to use the memory user object, and then saving it in the users dictionary, but the first solution commented sounds better for me.

1 Like

Hi @cincinnato, hope you are ok.

Now to graps the concept on storage and memory for Solidity it could be confusing.

To keep it on simple terms, think on memory has a volatile memory like RAM in pc. Meaning is a memory space that will only be used for the function operations, after it finish its execution, some values can be deleted.

While storage is more like saving data directly in the hard drive, but in this case is the blockchain, so basically is: if you need to save data permanently in the blockchain, you use storage.

If you have any more questions, please let us know so we can help you! :slight_smile:

Carlos Z.

Sorry Carlos, I think you confused points in your explanation, as it should be exactly the opposite. Memory is temporary data location and storage is persistent data location. For your reference I enclose the screenshot of the lesson where stated.

These points are very easy to understand. The problem is another one. It is not easy for people not used to write code to assimilate these concepts in the code lines. I have already seen the solution video lesson and I got it, but if I should understand in the code lines… well this is very hard, at least for me.33 - Data location

1 Like

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

}

QUESTIONS:

  1. Why can we use our struct “User” in the map “users” before having declared this struct???
1 Like