Thank you again, Jon! Good explanation!
Guys I need help I can’t still understand this Solidity well.pls if you have any material I can still read up pls help with it…
Hi @Phaxsam,
Sorry to hear you’re struggling with the course. But can you please be more specific about what it is you don’t understand. Then we will be able to help you. For example, is it this particular Data Location Assignment you are having problems understanding? If so, which specific code/syntax?
The videos are specifically designed for beginners, but you may need to watch some of them (or parts of them) several times, pausing to code the examples yourself in Remix. Otherwise what you are listening to may not really sink in. Don’t move on to the next video lecture until you have been able to reproduce the code you’ve seen in Remix and made sure that it compiles without any errors. If you get errors, you need to understand why and correct them before moving on. If you get stuck, then go to the forum discussion topic for that section of the course and spend time reading some of the posts. You will find a lot of useful, additional information in these discussion topics, and other students will probably have already asked similar questions to yours, and received answers and helpful advice. Often, the same concepts covered in the video are explained in different ways, which may be just what you needed. If your particular question hasn’t been covered, then post it; but it needs to be a question about something specific, including the actual code you don’t understand, or your own code which isn’t working.
I hope that gives you some good ideas about how to get the help you need
I’ve also noticed that you haven’t submitted any of your answers/code for the JavaScript course assignments, by posting them here in the forum. If you don’t post your work, then you won’t get any specific feedback or advice from us about it, meaning that there may be some key things you aren’t understanding and addressing at the right time. You will find this Solidity course very difficult to follow if you haven’t properly covered the material in the JavaScript course, because a lot of Solidity builds on this knowledge.
So my advice is that, if you haven’t already done so, repeat the JavaScript course, applying the advice I’ve given you in my last post to that course first, and post your answers/code for the assignments here in the forum for us to review
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;
}
}
Preformatted text
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
I changed the ‘memory’ to ‘storage’ for user variable in updateBalance function as follows:
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
yes…I’ll watch the videos again…thanks for the advice
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;
}
}
After a couple hours of trying to research and solve this i realized all i had to do was on line 16 change the code from “memory” to “storage”.
I learned so much more about solidity with the research i did for this one problem!
I deducted that the issue with the code is in “Update Balance Function”, specifically in line 16 where the code reads the following way:
16 user memory user = users[id];
I believe that the dynamic behind this exercise is to fully understand nature of the function and its the scope that we want to obtain. When we store variables in “memory”, this data will only be available whilst the function is being executed AND we want to be able to access the balance that has been updated in this function even after the function has been executed. In order for us to be able to do this, we need to point the data location to “STORAGE” NOT “MEMORY”, because “storage” will store the given value in the blockchain; “STORAGE WILL BE PERSISTENT THROUGHOUT THE BLOCKCHAIN”, I believe this is the keyword here, “persistent” throughout the blockchain.
Would anyone kindly add to my logic if indeed I have missed anything?
Can someone please help me understand if I missed something? I’m under the impression we were asked to identify and correct the code that was erroneous. I would really like to know if I missed something cause if I did, I wanna know what it was in order for me to work on the same thing everyone else is. lol
I understood that the erroneous code entailed data location and memory.
Thanks in advance!
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 newBalance) public {
require(id > 0, "ID sane value must be greater than zero");
//Don't use local function scope for state variables
//User memory user = users[id];
//user.balance = balance;
users[id].balance = newBalance;
}
function getBalance(uint id) view public returns (uint) {
return users[id].balance;
}
}
I thought about using require and assert to enforce the contract in the updateBalance() function in particular; however, I tested -1 for example but the run errored, so the strict typing of parameters is enforced, therefore not really required to demonstrate it.
Also, assumed balance is stored with the required number of decimal places as per the contract.
I updated the updateBalance
function to the following:
function updateBalance(uint id, uint balance) public {
users[id].balance = balance;
}
Nice solution @alanmichael
Yes… that’s often the way All the other things you learn about while researching are just as valuable as finding the actual solution to the problem!
Hi @JosephGarza,
Correct… can you post your solution so that we can check it? There are alternatives.
Correct again Although the syntax itself isn’t erroneous. It just doesn’t serve the purposes of this particular function, which as you rightly say is that…
But you are right that in this particular example the issue is related to using memory
as the data location of the value assigned to the user
variable.
Correct…it is possible, however, to solve the task by leaving this line and changing/adding other code. There are usually several alternative ways to solve coding problems. But usually certain solutions are more appropriate than others depending on the circumstances. In programming, in general, we usually want to aim for concise and/or readable code. In Solidity an important consideration is also the gas consumption. In this task, the more appropriate solutions do actually involve modifying the line you have highlighted.
Exactly right
Correct again. However, explicitly defining a variable with the data location storage
, is just one way to solve the task…
The simplest way to assign data to persistent storage is to reference a state variable or mapping without creating an additional local variable. However, sometimes using a local variable can be a useful intermediate step when performing more complex operations involving multiple properties and their values: it can help us to set our code out into separate logical steps, making it easier to read and understand.
All variables store values. However, values stored in local variables (defined within functions) are only stored temporarily whilst the function is executing. When local variables are defined with an elementary data type (integer, address, boolean) the syntax takes care of the temporary data location for us. However, when we define a local variable with a complex data type (string, array, struct instance) Solidity requires us to specify the data location. Specifying memory
creates a copy of the data and stores it temporarily in memory. But specifying storage
doesn’t create a copy of the data; instead, it creates a “pointer” (a reference) to a state variable or mapping, which enables data being handled within a function to be directly assigned to the contract state where it will be stored persistently on the blockchain.
Just one other observation…
The first word in a variable definition in Solidity is the data type, which in this example should be User
(starting with a capital letter).
user
(starting with a lower case letter) is the name (or identifier) of our temporary local variable.
user
stores an instance of the User
struct.
Looking forward to seeing your chosen solution! Let me know if anything is unclear, or if you have any further questions
function updateBalance(uint id, uint balance) public {
User memory user = users[id];
user.balance = balance;
}
Changing the data location of the variable to storage solves the problem, but it raises a few questions:
- Does the “storage” data location always create references when used within functions, or is another instance of User added to “storage”?
- is there a use case where the “storage” type would be used within the function and intended to occupy the storage of the contract but only be available to the one function?
copy/paste error: the corrected function is:
function updateBalance(uint id, uint balance) public {
User storage user = users[id];
user.balance = balance;
}
So, persistent. To sum it up, it is persistent throughout the blockchain.
And, I appreciate your shedding light on the capitalization of the first word when defining a variable.
And, it should be “User” with a capital letter, … why, kind Sir?
Jon, I could not stop thinking about my question. I really do not like to ask questions without doing some research prior. I mean, you went about saying that “user” with a lowercase “u” defines an instance of the User struct so I take it that the capital “U” in User, when used as the first word in the definition variable, is to … ? I will do some more reading up on this tomorrow. Thanks, man.
Nice solution @GreggyB
A few observations regarding your comments…
An input value of -1
throws an error because our id
parameter is defined as an unsigned integer (uint
). This data type will only accept integers >= 0
No… number values in Solidity can only be of type integer or unsigned integer (int
& uint
) i.e. decimals are not accepted. With values representing ether, we use wei; and so, because 1 ETH = 1,000,000,000,000,000,000 wei, decimals are not needed. We can convert wei values into ether in the frontend using JavaScript (e.g. with web3.js). Similarly, if our integer values represent tokens, a state variable in our contract can store the maximum number of decimal places 1 unit of the token can be subdivided into. Within the smart contract itself, we use integer values representing the smallest subunit of the token. If we want to display token values in the frontend as larger units with decimals, we can retrieve the “decimal places” value stored in the smart contract, and use that to convert the subunit values retrieved from the smart contract into more user-friendly values.
Just to be clear here… state variables (including mappings), by their very nature, cannot be defined within functions. So, within a function, in order to assign values to state variables or mappings, we can either:
(1) Assign them directly by referencing the state variable, or a specific mapping key, as you have done here:
(2) First create a local pointer to a specific struct instance saved in persistent storage (within the users
mapping, in our example). The pointer (essentially a reference) is created by defining a local variable with data location storage
and assigning a specific struct instance to it (in our example, by referencing a key within the mapping)…
User storage user = users[id];
(Note: this doesn’t create a temporary copy of the specific struct instance within memory. It creates a direct reference to the specific struct instance in persistent storage)
Then we update the specific struct instance in persistent storage via the pointer. We do this by assigning a value to the name we gave the pointer…
User storage user = users[id];
user.balance = newBalance;
(3) First define a local variable which has our predefined struct as its data type. As structs are complex data types, we need to specifiy the data location as memory
. This variable essentially creates a separate copy of a struct instance, which is saved temporarily in memory…
User memory user;
Next we can assign a value to this local variable. However, because this variable will only store its data temporarily, if we want the value to be reflected in a specific instance stored persistently within the contract state, we need to also perform that assignment, as follows…
User memory user;
user.balance = newBalance;
users[id] = user;
Let me know if anything is unclear, or if you have any questions