Data Location Assignment [OLD]

Hi @cryptopowers,

First of all, many apologies for the long delay in providing you with feedback on your solution to this assignment.

Your code works, but all you are doing in the additional line of code is repeating the functionality of the addUser function, as well as including additional references to the temporarily-created instance user, which you don’t actually need (as you are already referencing the User struct in permanent storage.

Whereas addUser does the same with:

users[id] = User(id, balance); 

You will also notice that by removing the unnecessary references to user, the previous two lines are now superflous i.e. they can also be removed as they now don’t affect the third line that you’ve added and also slimmed down.

However, instead of updating both the ID and the balance, we only want to use the updateBalance function to update balances of existing users. The ID will already have been assigned in the addUser function and, by its very nature, won’t need to be updated like the balance. We only need to include the ID as an input parameter in order to be able to map the new balance to the correct user.

So we only want to update the mapping’s permanent storage with a user’s new balance, which can be achieved as shown in this post.

I hope that’s clear. Just let us know if you have any questions.

Keep on learning! :muscle:

2 Likes

Hi @Chakingo,

Firstly, many apologies for the long delay in providing you with an answer to your question about this assignment.

This is because the 0 you are getting is not related to the input id value of 1 . The 0 simply indicates the first output. If you go back to the getter in the HelloWorld contract, you will see that we output 4 values: name, age, height, senior (which had the indices 0, 1, 2, 3, repectively). So whilst you only ever output one value (the balance), you will always see 0

The input id value is only used to retrieve the associated User from the users mapping, and this user’s balance. However, we could easily include the user’s ID (and also identifiers for both the ID and balance, just like we had for name, age, height and senior) by modifying our getBalance function as follows:

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

// addUser input: 1, 10
// getBalance input: 1
   // => 0: uint256: _id 1
   // => 1: uint256: balance 10
// updateBalance input: 1, 20
// getBalance input 1
   // => 0: uint256: _id 1
   // => 1: uint256: balance 20

I hope that answers you question and makes things clearer :slight_smile:

3 Likes

Hi @lucas,

First of all, many apologies for the dealy in providing you with feedback on your solution to this assignment.

This is an excellent solution, and the additional constraints you’ve added successfully deal with the weaknesses that remained in the original exercise.

However, I would question whether the newUser modifier is needed, because I can’t see when you would need to use it again. Would it not be simpler just to place this modifier’s two require functions directly within the addUser function body?

Also, take a look at this post which explains why your first solution (while it does work) is inappropriate. Had you already realised this?

1 Like

Nice solution @Juan_M_Villaverde :ok_hand:

And welcome to the forum! Great to have you here! :smiley:

1 Like

Hi Jonathon

Thanks for the reply. I did see that I could have created the fix differently as soon as I sent it. I did not want to replace the original lines above as they could be used for some other calculations and I left them for reference also. That is what I was thinking at the time in any case.

I very much appreciate the response…

Sincerely

Kelly Powers

1 Like

@jon_m
Hello. Thanks for your reply.
I used the newUser modifier to improve the code readability. Of course it would be simpler to include the code in the addUser function body. I don’t know what it changes about contract cost (gas) with or without the modifier.

About my first solution I did a mix-up in the comments sorry. My first solution was just one line:

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

I realized reading others solution this wasn’t right cause you don’t need to update the id but only the balance . But I kept the line of code there just to be honest.

1 Like

Thanks Jon for clarifying this a bit. I understand what’s up with the output number now, although I found the exercise confusing since I was supposed to type in an age and then the answer showed 0 regardless. I mean what then was the point of submitting an age?

I have no recollection of any HelloWorld contract. [OLD] Ethereum programming 101 has been about Dog contract since scratch. So no mentions of height or senior this far for me. Maybe this is a mix up because there are now also a new course? (I was recommended to do the old one first.)

1 Like

pragma solidity 0.6.10;
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

Issue is that updateBalance function was using memory instead “storage”.
So the data was not been saved persistancely.
By only changing the data location, the contract work.

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

1 Like

Hey @lucas,

Now that would be a useful test to perform whenever you have time. I’d be interested to know the results :slight_smile:

That’s great that you worked that out. I think it’s really helpful for other students when we’re “honest” about our initial attempts, and include them as well, so I do encourage you to do that, but always try to include an explanation about why it wasn’t suitable, it’s weaknesses, or why it was wrong (just like you have in your comment above) as that makes including it in your post a really helpful learning point for others, who are bound to be going through the same sorts of steps and thought processes.

Continue experimenting and developing your own extensions to the exercises, as that’s the best way to progress faster. Don’t hesitate to include them here in the forum either (with some comments about why they improve things, or maybe your reservations, questions, or any possible weaknesses you think there might be).

Changing ‘memory’ storage in the updateBalance function to ‘storage’ is the solution I utilized however I believe this is the most expensive solution so while it worked, it likely is not the best solution as it is not cost-efficient.

I’m still wrapping my brain around passing, and copying, and setting variables so I presume this will get all ‘sorted’ soon.

cheers

2 Likes

Hey Hannes,

Glad that helped a bit.

I have only ever seen the new 101 course to be honest, and in this exercise in the new course there is no age, only updating an ETH balance. No dogs either :joy:

Sorry to confuse you by going on about HelloWorld, height and senior: that’s all in this exercise in the new course, which everyone else who is posting here is doing. It does seem strange that you’ve got the same forum discussion to comment in. I’m going to check on this with a colleague, who will know about the old course, to clarify a few things.

But it sounds as though, by reading between the lines, picking up on the concept I was trying to get across (and ignoring my ramblings about HelloWorlds, heights and seniors lol) that you now understand why you were getting 0 every time and not the ID of 1 … and also that if you return 2 values then you’ll have 0 then 1… 3 values: 0, 1, 2 etc. (like index numbers).

1 Like

Nice solution @kenn.eth :ok_hand:

Just to clarify, we aren’t changing the data type (this is still a User struct) just the data location (i.e. memory to storage). But I’m sure that’s what you meant :wink:

2 Likes

Hi @John_Okoye,

That’s correct… although cost-efficiency is obviously relative, and depends on other factors such as how many times this particular transcation needs to be executed etc. The difference in practice may turn out to be immaterial (i.e. trivial) and so without further information, we can only really say at this stage that it’s more expensive than other solutions.

These concepts, and more specifically the terminology and the liberal way in which it can be used sometimes, do take a while to truly “click”. I conceptualise things as follows:

Passing (but not parsing) is what we do with values when we call/execute a function. When a function is called/executed, both in Solidity and JavaScript, we can pass values into that function by including them as parameters within the parentheses placed after the function name/identifier in the function header. I guess you could see passing as being synonymous with inputting because these values are effectively the inputs into the function, as opposed to the outputs which are returned by the function. A value can also be passed into a function by reference to the variable it has been assigned to, and so, here, you could say that you are passing a variable, the advantage being that, whatever value that variable holds when the function is executed will be passed into the function.

Setting variables is when we reassign their value (or assign a value when the variable was originally declared as undefined. This can be done by a straightforward reassignment e.g.

// JavaScript
let x = 10;
x = 20;

Or it can be done within a function (called a setter) specifically designed for this purpose, and which adds more “control management” to the reassignment (or setting) operation.

Likewise, we can have functions called getters, specifically designed to retrieve the values currently assigned to (or held by) certain variables, and also to provide some kind of added “control management”.

I’m not really sure about what you’re referring to with the term copying. I haven’t come across that as a specific term describing a specific type of programming operation. Maybe someone else can chip in here…
I guess you could say that in the following example…

// JavaScript
let x = 10;
let y = x;

…the value 10 has been copied from variable x to variable y… but I’m clutching at straws to be honest :wink:

Anyway, I hope I’ve helped to add a bit more clarity to the mystical arts of passing and setting :mage: :smile:


By the way, please don’t post screen shots of your code, because anyone who wants to run it or check it, can’t, because they can’t copy and paste it into their text editor. Also it’s much clearer and easier for people to see and read code which has been copied and pasted into your post and appropriately formatted. Thanks :pray:

1 Like

Appreciated very much! It appears there is a generations conflict of sorts going on here for learning and part of that I think is my ‘rigid’ thinking which needs to change…for there is nothing new under the sun, you are right in that ‘inputting’ is how I, GenX, think but when you have GenZ re-branding with ‘pass’, it really throws me for a loop!

I think input, inputting and inputted, that is the structure in functions…but to be ‘cool’, the new lingo is pass, passing, and thrown?

Seriously this ‘throws’ me in a tizzy but using the words of a GenZ: ‘Get over it’, lol.

Thanks for enlightening me…more pleasant environment than the ‘ignore ignorance’ attitude in the live chats!

1 Like

I’m in stiches here with your comments :joy:
Thanks for brightening up my Wednesday morning :slight_smile:
I’m definitely gonna start saying “…so I’ve thrown that variable into that function…” :joy: … so cool :sunglasses:

1 Like

man, its a different dialect they are teaching in…seriously, same language, but can really be challenging. Hilarious sometimes when you see subtitles on a news broadcast when someone is actually speaking English, but their dialect and accent are so strong the average person has no idea what they are saying. I’m going to write a formal complaint to Ivan and request that they place these subtitles in Filip’s lessons, lol

pragma solidity 0.6.6;
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 change “memory” to “storage”.

1 Like

Ooooh yeah John thanks for your attention! That was what i mean. The data location, not data type.

2 Likes