Solidity Tutorial – Intro To Solidity Programming Language
In this lecture we are going to talk about contracts, constructors and functions.
OK, let’s dive right in.
Let’s first see what is the structure of a solidity source file.
Here we can see a sample contract.
On the top of every solidity file there is the so called version pragma, which tells us the lowest version of solidity supported by the contract.
After that we have the contract and its name.
Inside it we can put variable declarations, mappings, constructors, functions, modifiers etc.
Now, let’s see a sample contract.
Here we have two contracts called Owned Token and Token Creator. You can have multiple contracts declared in one solidity file.
As you can see we can also call contracts from other contracts as in this example.
After this we have the variable declarations owner and name, which are used to store the address of the owner of the contract and the name of the contract.
Just below them we have a constructor. Keep in mind that several versions before a constructor was declared as a function with the same name like the contract. However, now we use the keyword constructor.
So a constructor is a function that runs only once when the contract is deployed to a network.
When we deploy this contract we can send the variable name with it. This variable is saved in the state variable name and our wallet address, from which we deployed the contract with, is saved in the state variable owner.
Now we can use this reference to check and restrict functions to be used by someone who is not the owner of the contract.
Ok, now lets see what is the structure of a function.
If you are familiar with JavaScript., functions look a lot like the ones there. However, we have some additional modifiers. After the function name and the variables that the function receives, we have visibility declaration, state mutability and the return types of the function.
For visibility we can have public, private, internal and external. For the state mutability we can have pure, view and payable. And in order to return some variables from a function at the end we should add the keyword ‘returns’ and in brackets the type of variables that we want to return. Here we can return more than one variable, so keep that in mind.
Ok, let’s look at the different types of visibility in more detail. As we said we have 4 different types of visibility – public, external, internal and private.
Those visibility declarations can be applied both to functions and variables except for the external keyword which is only for functions.
When we declare a function the default visibility of it is public. Basically we can call this function internally and externally and everyone has access to it.
The external keyword works almost the same, however, when you try to call the function internally (from within the contract or another function in the contract) you will need to use the ‘this.’ in order to access it.
This might seem a little inconvenient, however external functions can cost less gas sometimes, because sometimes they are more efficient when they receive large arrays of data.
We can also have internal functions that can only be accessed internally from the current contract or from contracts deriving from it.
And last but not least, we have private functions which can be called ONLY from the contracts they are defined in. The are usable only internally in the same contract.
Now let’s see an example of external and public functions.
Here we have а Sample contract.
At the first line as you can see I have declared a variable as external. If you try to do that you will get an error and the contract will not compile. Remember – state variables do not have an external visibility.
However, here I have created public and external functions. Both of them do the same operation, but the external function will cost less gas in the end. External functions are more efficient when they receive large arrays of data so you can use them to make your contract more efficient.
And at the end I have declared a function in which i try to call the external function test2. However, I needed specify it as this.test2() in order to access the external function internally.
So remember if you want to call external functions internally you need to add the keyword this. In front of the function.
Now, let’s look at an example of internal and private functions.
Here we have 3 contracts C, D and E.
Contract C has one private function, two public functions and an internal function called compute.
In contract D if we try to call the function f of the contract C we are going to get an error because the function is declared private and is visible only inside the contract that it is defined in.
Also if we try to call the function compute from contract D we are also going to get an error because contract D is not derivative of contract C.
However, contract E is derivative of C. We declare this with the keyword ‘is’ as you can see in the example. If you have any prior programming knowledge this is called inheritance.
Because, our contract is derivative of contract C we can now call the the compute function as it is internal member.
Now, let’s talk about the state mutability of function.
We have three different modifiers for that.
We have view, pure and payable.
If we declare a function to be a view function we basically promise no to modify the state.
Pure functions are derivatives of view functions. However, pure functions promise not only not to modify the state, but also not to read from state.
In the next slides we will see more specific restrictions to those functions.
The last state mutability we can have is payable. Basically, the functions that are annotated with this modifier can receive ether and can make operations with those ethers.
Now, let’s look at some examples.
Here is an example of a view function that you can create.
This function takes two variables “a” and “b” and returns “a” times (b + 42) + now.
Now is a global variable that gives you the time now as a timestamp variable.
When you have a view function you CAN NOT write to state variables, emit events, send ether, call functions that are not pure or view, etc. I have listed the things that are not allowed in view functions on the right side here.
Now… Pure functions have the same restrictions as view functions as well as that they can’t read form state variables.
In this example we have 3 pure functions. The first two functions take variables x and y and do some mathematical operations and return the result. The third one just returns a string of “You are AWESOME!”. Those are some perfect examples of pure functions that you can use.
However, there are some additional restrictions that you should keep in mind like that you can’t access this.balance, <address>.balance, blocks, tx, msg variables or call functions that are not marked as pure.
Now let’s see and example of a payable function.
In order to receive Ether you need to provide the ‘payable’ keyword to a function, otherwise the function will reject all Ether send to it.
In this example contract we have a public declared variable amount of 0 and we have a payable function pay me. The variable msg.value gives the amount of ether that was send to the function and adds it to the variable amount.