WTF Solidity: 3. Function
Recently, I have been revisiting Solidity, consolidating the finer details, and writing "WTF Solidity" tutorials for newbies.
Twitter: @0xAA_Science | @WTFAcademy_
Community: Discord|Wechat|Website wtf.academy
Codes and tutorials are open source on GitHub: github.com/AmazingAng/WTFSolidity
Function
Here's the format of a function in Solidity:
function <function name>(<parameter types>) [internal|external] [pure|view|payable] [returns (<return types>)]
It may seem complex, but let's break it down piece by piece (square brackets indicate optional keywords):
function
: To write a function, you need to start with the keywordfunction
.<function name>
: The name of the function.(<parameter types>)
: The input parameter types and names.[internal|external|public|private]
: Function visibility specifiers. There are 4 kinds of thempublic
is the default visibility if left empty:public
: Visible to all.private
: Can only be accessed within this contract, derived contracts cannot use it.external
: Can only be called from other contracts. But can also be called bythis.f()
inside the contract, wheref
is the function name.internal
: Can only be accessed internal and by contracts deriving from it.Note 1:
public
is the default visibility for functions.Note 2:
public|private|internal
can be also used on state variables. Public variables will automatically generategetter
functions for querying values.Note 2: The default visibility for state variables is
internal
.
[pure|view|payable]
: Keywords that dictate a Solidity functions behavior.payable
is easy to understand. One can sendETH
to the contract viapayable
functions.pure
andview
are introduced in the next section.[returns (<return types>)]
: Return variable types and names.
WTF is Pure
and View
?
When I started learning solidity
, I didn't understand pure
and view
at all, since they are not common in other languages. solidity
added these two keywords, because of gas fee
. The contract state variables are stored on block chain, and gas fee
is very expensive. If you don't rewrite these variables, you don't need to pay gas
. You don't need to pay gas
for calling pure
and view
functions.
The following statements are considered modifying the state:
Writing to state variables.
Emitting events.
Creating other contracts.
Using selfdestruct.
Sending Ether via calls.
Calling any function not marked view or pure.
Using low-level calls.
Using inline assembly that contains certain opcodes.
I drew a Mario cartton to visualize pure
and view
. In the picture, the state variable is represented by Princess Peach, keywards are represented by three different characters.
pure
: Functions containingpure
keyword cannot read nor write state variables on-chain. Just like the little monster, it can't see or touch Princess Peach.view
: Functions containingview
keyword can read but cannot write on-chain state variables. Similar to Mario, able to see Princess but cannot touch.Without
pure
andview
: Functions can both read and write state variables. Like theboss
can do whatever he wants.
Code
1. pure v.s. view
We define a state variable number = 5
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract FunctionTypes{
uint256 public number = 5;
Define an add()
function, add 1 to number
on every call.
// default
function add() external{
number = number + 1;
}
If add()
contains pure
keyword, i.e. function add() pure external
, it will result in an error. Because pure
cannot read state variable in contract nor write. So what can pure
do ? i.e. you can pass a parameter _number
to function, let function returns _number + 1
.
// pure
function addPure(uint256 _number) external pure returns(uint256 new_number){
new_number = _number+1;
}
Example:
If add()
contains view
, i.e. function add() view external
, it will also result in error. Because view
can read, but cannot write state variable. We can modify the function as follows:
// view
function addView() external view returns(uint256 new_number) {
new_number = number + 1;
}
Example:
2. internal v.s. external
// internal
function minus() internal {
number = number - 1;
}
// external
function minusCall() external {
minus();
}
Here we defined an internal minus()
function, number
will decrease 1 each time function is called. Since internal
function can only be called within the contract itself. Therefore, we need to define an external
minusCall()
function to call minus()
internally.
Example:
3. payable
// payable: money (ETH) can be sent to the contract via this function
function minusPayable() external payable returns(uint256 balance) {
minus();
balance = address(this).balance;
}
We defined an external payable minusPayable()
function, which calls minus()
and return ETH
balance of the current contract (this
keyword can let us query current contract address). Since the function is payable
, we can send 1 ETH
to the contract when calling minusPayable()
.
We can see that contract balance is 1 ETH
in return message.
Example:
Coding Exercise
SoLive The first open-source lightweight Solidity IDE that can be easily integrated into websites, documents, and tutorials. Powered by WTF Academy, Inspired by Remix-IDE and react-live.
Try to complete the following contract and make it compile!
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract Quiz3{
// complete following funciton, let it return the sum of x and y
function sum(uint x, uint y) external{
}
}
Summary
In this section, we introduced solidity
function type. pure
and view
keywords are difficult to understand, since they are not common in other languages. You don't need to pay gas fees for calling pure
or view
functions, since they don't modify the on-chain data.