Functions are used divide code into chunks. It makes the code cleaner, easier to understand and more efficient. Functions also prevent the need to write the same thing over and over again, because a function can be called multiple times.
declaration of a function
In Solidity a function is declared by the function keyword followed by the name of the function. The function name has to be unique and can not match any of the reserved keywords in Solidity. A function can also accepts one or more parameters, they are specified by the name and data type of each parameter within the parenthesis. The return keyword is optional, because a function doesn't need to return a value. If the function should return a value then data type of the return value has to specified after the returns keyword within parenthesis. Also the scope has to be specified.
contract Functions{
function add(uint num1, uint num2) external pure returns (uint) {
return num1 + num2;
}
function subtract(uint num1, uint num2) external pure returns (uint) {
return num1 - num2;
}
}
A function can be called within another function with the following syntax: function(parameter);
return values
The returns keyword in the function declaration is optional. Not all functions have return values in Solidity.
If values are returned there a two ways to do so:
- by using names
- by directly returning the values
return values by using names
In Solidity functions can return named outputs. This is more gas efficient because one copy operations is dropped. To return named outputs, it is necessary to specify the return names in addition to the data types in the returns statement.
// return named outputs to save gas
function add(uint num1, uint num2) external pure returns (uint result) {
result = num1 + num2;
}
return values directly
The most common way to return values in Solidity is by using the return statement. This is less gas efficient than named outputs but increases the readability of the code.
function add(uint num1, uint num2) external pure returns (uint) {
return num1 + num2;
}
If values are returned directly the name of the return variable is omitted and the value is directly returned after the return keyword.
return multiple values
It is also possible to return multiple values by wrapping the return values in parenthesis. The data type of every return value has to be specified as well.
// return multiple values in Solidity
function calc(uint num1, uint num2) external pure returns (uint add, uint sub) {
add = num1 + num2;
sub = num1 - num2;
return (add, sub);
}
To capture multiple return values of a function we have to destruct the output. In the first example below, the multiple return values are captured and assigned to two variables. In the second example the first value is omitted and only the second value is assigned to a variable. It is important to not forget the comma when omitting values.
// capture multiple return values
function catchMany() public pure {
// catch both variables
(uint add, uint sub) = calc(123, 1);
// omit the first variable
(, uint _sub) = calc(123, 1);
}
visibility of functions
There are 4 different configurations for the visibility of functions in Solidity.
visibility |
description |
private |
private is the most restrictive visibility, it restricts the function to be called from within the same contract |
internal |
restricts the function to be called from within the same contract and all contracts that inherit from it |
external |
restricts the function to be called from outside the contract (have to use this to call function within the contract) |
public |
no restriction, the function can be called from inside or outside the contract |
view vs pure functions
The difference between view and pure functions is that view functions can read information from the blockchain while pure functions can not. The following example demonstrates the difference between a view and pure function in Solidity: The viewFunction() reads the state variable n, while the pureFunction() doesn't read any state variable.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
// view and pure functions in Solidity
contract ViewAndPure {
uint public n;
// reads state variable n and returns it -> view function
function viewFunction() external view returns (uint) {
return n;
}
// reads no state variables -> pure function
function pureFunction() external pure returns (uint) {
return 1;
}
}
functions outside of contract
A function can be declared outside a the contract block in
Solidity. This is useful because then the function can be imported into another file. During the
import, it is also possible to declare aliases to prevent naming collisions.
In the following code, the function add is declared outside of the contract and then used in the test function within the contract. It can also be imported by another file.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
// functions outside of contract
function add(uint num1, uint num2) pure returns (uint) {
return num1 + num2;
}
contract FunctionsOutsideContract {
function test() external pure returns (uint) {
return add(1, 2);
}
}