Solidity Basics

HI Carlos, Hope you are well.
Your replies are helping me to learn about the logics which computer can understand,

  1. from your reply, i understood that mapping does not return struct with string and uint , it only returns integers like, addresses, balances. I understand now that mapping is to get value from address primarily and it does not take in strings value because it is mapping, not array.

  2. mapping ( address => User) users;

// means it is a mapping named users which each key address will return the value based on struct. Correct ?

function addUser ( uint address, uint balance) public {
users[address] = User ( address , balance);
} // Correct ?

// This means that if we enter 1,100 into addBalance function in remix, it will throw an error because it requires a address type, it will not accept uint. Correct ?

While users{id] = User storage user ;
// does not make sense in the updateBalance function, because a storage variable needs to be created first before it is ā€œpushedā€ into ( users[id]), but rather
User storage user = users[id];
// a storage variable named user is created based on struct User, and is ā€œpushedā€ into user[id], Correct ?

  1. As for :
    function addUser (uint address, uint balance) public {
    users[id] = User ( address, balance );
    }
    is users[id] = User (id, balance);
    also the same as User ( id, balance) =users[id] ?

Just like, b=2 being the same as 2=b ?

Sorry if i am confusing you. Thank you for your patience.

Hey @M.K

from your reply, i understood that mapping does not return struct with string and uint , it only returns integers like, addresses, balances.

This is not correct.
A mapping just points to a slot in the computer memory, this slot can contain all kind of data such as integers, strings, addresses, arrays, structs or other mappings.
A mapping is structured as follow:

(key => value) mappingName;

You always have to provide a ā€˜keyā€™ in order to access the ā€˜valueā€™.

Consider this contract:

pragma solidity ^0.7.5;
pragma abicoder v2;

contract BunchOfMappings {
    
    struct TestStruct {
        string name;
        uint age;
    }
    
    mapping(address => TestStruct) testMapping;
    
    function set(string memory _name, uint _age) public {
        testMapping[msg.sender] = TestStruct(_name, _age);
    }
    
    function get() public view returns (TestStruct memory) {
        return testMapping[msg.sender];
    }
}

The function ā€˜set()ā€™ asks for a name and age and set the struct with the data input by the user.
The function ā€˜get()ā€™ returns the struct related to ā€˜msg.senderā€™.

Screenshot 2021-04-08 at 09.35.52

  1. mapping ( address => User) users;
    // means it is a mapping named users which each key address will return the value based on struct. Correct ?
    function addUser ( uint address, uint balance) public {
    users[address] = User ( address , balance);
    } // Correct ?
    // This means that if we enter 1,100 into addBalance function in remix, it will throw an error because it requires a address type, it will not accept uint. Correct ?

All correct. But this is in contracts with your first question that I answered above :slight_smile:

User storage user = users[id];
// a storage variable named user is created based on struct User, and is ā€œpushedā€ into user[id], Correct ?

Correct.

also the same as User ( id, balance) =users[id] ?
Just like, b=2 being the same as 2=b ?

This is not correct.
Just by trying to compile this you will get an error User ( id, balance) =users[id] .
Also this is not correct Just like, b=2 being the same as 2=b ?
In programming you assign a value to a variable not the opposite:

Say that b=2 means that you are giving a value to a variable called ā€œbā€.
Say that 2=b means that you are assigning a value of ā€œbā€ to number two.

Happy learning,
Dani

1 Like

Hi everyone!
can someone help me, how can i see insmart contract code if its possible for project to mind additional amount of tokens or not?
thanks)

I am having a hard time getting remix to work for me. Iā€™ve opened a new file but nothing happens when I try and type something into the editor. When I create a new file, it calls is a workspace rather than a .sol file.

Hi @Bojo

Can you clarify your question?

Hey @CryptoDance

Seems like you are creating a workspace rather than a new file.
Click here:

image

Remix has also a documentation is needed :slight_smile:

Screenshot1

Would anyone be able to tell me what I am might be doing wrong in this function. Looks like the issue is in line 20 but not sure. Thanks in advance for the help.

Following up on the Arrays class I tried to add a similar functionality for adding and returning string values of wallet addresses to an array. However it wouldnā€™t let me return the array without adding the line ā€œprama abicoder v2;ā€. What does this line solve and is there a way to solve this with the line of code mentioned above? Itā€™s working now however Iā€™d like to get a deeper understanding of what itā€™s actually solving.

This is the code, itā€™s highly possible Iā€™ve made some sort of mistake in the usage or placement of some keywords thus requiring me to use this extra line.
stringArray

1 Like
pragma solidity 0.7.5; 

contract balancetransfer { 
    
    mapping (address=>uint)balance; 
    
    function addBalance ( uint _toAdd )public returns(uint) { 
        balance [msg.sender]+= _toAdd; 
      return balance[msg.sender]; 
        }
    
    function getBalance () public view returns ( uint){ 
        return balance[msg.sender];    
    }
    
    
  
  function transfer (address recipient, uint amount )public  { 
    
    _transfer (msg.sender,recipient, amount ); 
  }
    
    function _transfer ( address from, address to, uint amount)private { 
        balance [from] -= amount; 
        balance [to] += amount; 
        
    }
    
    
}

What is the purposes of returns (uint ) in below function ?

function addBalance ( uint _toAdd )public returns(uint) { 
    balance [msg.sender]+= _toAdd; 
  return balance[msg.sender]; 
    }

Is it to update the value after amount is added?
Doesnt the value get updated by itself itself after amount is added to it ?

I dont quite understand the returns () .
Sometimes, it is used to return the value in msg.sender in the getBalance function , that one i understand,

Please explain more to me about purposes of returns ( ā€¦ ) when they are used in functions.
Thanks

1 Like

From the quiz, i understand that Public functions automatically gets a getter function for us.
What does getter function means ? A function that return a value without the need to returns(uint) for example ?

1 Like

Hi Daniele,

I have a question on = and ==, which i want to check on

b==2, is the same as 2==b ?
== is basically used for value and value ?

while = is used for key and value, example
b=2 // b is the key, and 2 is the value, Correct ?

Please enlighten me on this part. Its still a bit confusing.
Cheers

Hi @M.K

A getter function returns the value of a given variable.

b==2, is the same as 2==b ?
== is basically used for value and value ?

yes correct. You are comparing two values so you can just switch their order and the result will be the same.

Cheers,
Dani

1 Like

Hi @M.K,

Noā€¦
returns in the function header defines the data type of the value returned from the function i.e. the data type in the parentheses (here, the uint in returns(uint) must match the data type of whatever value comes after the return keyword in the function body:
return balance[msg.sender];
The value returned from this function is an unsigned integer (the balance mapped to the function callerā€™s address in the mapping called balance). The function caller is the msg.sender.
In JavaScript we donā€™t have the extra returns() in the function header. In Solidity we do and we need it because it is part of the syntax. In JavaScript we donā€™t have to define the data type of our values, but in Solidity we do, so this may be why Solidity requires the extra returns() (although this is just my assumption).

Yes, the balance is updated in the first line of code in the function body:

We could just finish the function with this, and the mapping would still be updated correctly. We donā€™t need to return a value to do that. But the writer of this function has decided that as well as updating the balance, they also want the function to output the new balance value, so that this information is received by the caller of the function. Without it, you wouldnā€™t see the new balance in the Remix console when you click the function name button to call it.

Getters just return values. They donā€™t update anything (they donā€™t change the internal state of the contract). Thatā€™s why they have the function type view. Here is the getter:

Can you see itā€™s exactly the same as the addBalance function, but without the line of code which updates the balance and changes the contract state?
As you say, here, returns() ā€¦

In the addBalance function, return and returns() do exactly the same job ā€” they return the value of the callerā€™s (msg.sender) balance from the mapping. The only difference is that the addBalance function only returns the new balance after it has just been increased.

A setter changes the contract state (assigns a value to a state variable, mapping or array etc.) but it doesnā€™t have to return a value. This would be a classic setter:

function addBalance (uint _toAdd) public { 
    balance [msg.sender]+= _toAdd; 
}

Then the user could retrieve the new balance with the separate getter (see above).
The function that has confused you, basically does the job of both the getter and the setter within the same function. However, with the addBalance function, you will only ever get the new balance after you have just increased it. If you want to just get the balance, without increasing it, then you need to call the getter.

3 Likes

Just to follow on from what Iā€™ve just explainedā€¦

A getter function is what I have described above:

Public variables (not functions) automatically give us a getter. This getter does exactly the same thing as the standard getter we can write ourselves (as above). Itā€™s just that we donā€™t need to write it ourselves when the data we want to ā€œgetā€ is stored in a variable marked public. Itā€™s still the same getter, performing the same low-level operations, but itā€™s a built-in feature of Solidityā€¦ like shorthand :slight_smile:

2 Likes

Hey @Bitborn,

Your problem is that your function header (line 19) ends with a semi colon ( ; ) and not an opening curly bracket {

Hi @maxsmeets1996,

This is a very good question. Unfortunately, the explanation as to why you couldnā€™t return an array of strings without adding the line of codeā€‚ pragma abicoder v2 ā€‚is not straightforward, and requires an understanding of the EVM bytecode and Ethereum Contract ABI (Application Binary Interface), which is what the Solidity compiler generates when it compiles the code you have written in the high-level Solidity programming language. Below is a link to an article which I think introduces these concepts quite well, and should be enough to get you started with your own research.

https://medium.com/@eiki1212/explaining-ethereum-contract-abi-evm-bytecode-6afa6e917c3b

Once you have a basic grasp of these concepts, then you can start to understand why older versions of Solidity didnā€™t allow us to return certain complex data types (e.g. like your array of strings). It was an issue associated with the standard ABI encoder, and developers had to find alternative workarounds. However, this issue has gradually been resolved:

  • First, there was ā€‚pragma experimental ABIEncodervV2
  • Then, we could use ā€‚pragma abicoder v2
  • And now, from v0.8.0 the ABI encoder v2 is activated by default, which I think basically means we donā€™t have to explicitly tell the compiler to use it anymore. You could try changing the Solidity version in your contract to v0.8.0, removeā€‚ pragma abicoder v2 ,ā€‚and see if the compiler will allow you to return your array of strings without it.

https://ethereum.stackexchange.com/questions/58698/typeerror-this-type-is-only-supported-in-the-new-experimental-abi-encoder?rq=1

So, no, you havenā€™t made any mistakes. If you are compiling using v0.7.5, then you need to add the extra line if you want to return an array of strings.
Iā€™ve had a quick look at your code, and it all looks OK. In the future, post a formatted copy of your code, and not a screen shot, because otherwise we canā€™t copy your code and execute it ourselves, to check it.

Just one other thing ā€” Iā€™m sure you already know that in Solidity we use the data type address instead of string for Ethereum wallet addresses. Were you just using string to practise using the memory keyword? If you change the data type to address then Solidity lets you return an array of addresses ā€‚address[]ā€‚ without having to instruct the compiler to use the ABI encoder v2ā€¦ Iā€™ll leave you to find out why, whenever you feel ready and brave enough, because it will involve some in depth research :wink:

2 Likes

Hi Jon, Thanks for the explanations. I understand that public variable get us the getter automatically now.
But what led me to think public function gives us a getter is because of the visibility quiz question and answer below

==================================================
For which visibility levels will solidity automatically create a getter function for us?

Answer : Public

I thought that it means that if you put a public in the function header, then the getter is there automatcally.

But i also realised that many functions with public visibility has returns () in them too.

Perhaps i do not understand the question and answer stated. Can you clear my doubt on this ?

Cheers,

1 Like

Hey @M.K,

Visibility levels of either state variables (including arrays and mappings) or functions determine who or what can access those variables or functions. For example, a function with public visibility means that the function can be called from anywhere: from an external service (e.g. from Remix, or from the frontend interface of a dapp), from another smart contract, or from another function within the same smart contract.

A state variable (or array or mapping) with public visibility can also be accessed to the same extent. It makes sense that we can write code within a function body that can get or set the values stored in public variables, but the only way for an external service to get these values is via a getter. If we have a private state variable, then we need to write our own public getter to a get the values for us. The public getter can access the private state variable if it is in the same smart contract ā€” private visibility restricts access to within the same contract. Then, using an external service such as Remix, we can call the public getter to retrieve the values. However, if the state variable itself has public visibility, then Solidity automatically creates a getter function for us. Itā€™s just that we donā€™t actually see the explicit code, because the getter functionality is built into the Solidity syntax i.e. when the compiler processes the Solidity code ā€‚ dataType public stateVariableName;ā€‚(e.g. string public myMessage; ) ā€‚ it knows it needs to generate the EVM Bytecode for a getter as well.

I hope that makes a bit more sense. It does take a while to fully grasp these concepts, so well done for trying to understand whatā€™s really happening! :+1:

1 Like

Just to return to the specifics of your questionā€¦

Hopefully, after my explanation above, you can now see that the ā€œautomatic getterā€ is only something that is needed for a public state variable (or array or mapping). If a function is given public visibility, this has nothing to do with whether a getter is needed for it to perform its job: it simply means that the function can be called from anywhere (as Iā€™ve described above).

1 Like

Hi Jon, That clears the doubt i have, Thanks

One more question regarding this matter
If i declare a state variable without public eg
address myAddress ;

does this mean this will be private automatically and not be accessible for external contract or frontend interface of dapp ?

meaning i only put public when i declare state variable, if i want the state variable to be accessible for other external contracts, and dapps ?

Cheers,

1 Like