The default function type and doesn't get specified as a modifier.
The function can modify the state of the contract on the blockchain. Non-constant functions can write to the contract's storage, emit events, create other contracts, and use selfdestruct.
view
Doesn't cost gas when called directly (externally by a user).
Does cost gas when called by another function or contract.
Reads the state of the blockchain but can't modify it.
pure
Doesn't cost gas when called directly.
Does cost gas when called by another function or contract.
Does not read the state of the blockchain, only memory and calldata.
Selector and Signature
// Example Function Selector:0xa9059cbb// Example Function Signature:"transfer(address,uint256)"
Code Conventions
Function parameters and private function names start with an underscore _
Default visibility specifier when none are specified.
Internal functions can only be called inside the current contract (more specifically, inside the current code unit, which also includes internal library functions and inherited functions) because they cannot be executed outside of the context of the current contract.
Calling an internal function is realized by jumping to its entry label, just like when calling a function of the current contract internally.
Those functions and state variables can only be accessed internally (i.e. from within the current contract or contracts deriving from it), without using this.
external
External functions consist of an address and a function signature and they can be passed via and returned from external function calls.
Can be called from outside, canβt be called from inside (functions from same contract, functions from inherited contracts).
External functions are part of the contract interface, which means they can be called from other contracts and via transactions.
An external function f cannot be called internally (i.e. f() does not work, but this.f() works).
External functions are sometimes more efficient when they receive large arrays of data.
private
Private functions can only be called from inside the current contract, even the inherited contracts canβt call them.
Private functions and state variables are only visible for the contract they are defined in and not in derived contracts.
public
Public functions can be called from anywhere.
Public functions are part of the contract interface and can be either called internally or via messages.
For public state variables, an automatic getter function is generated.
Function Declarations
A function declaration in Solidity looks like the following:
functioneatHamburgers(stringmemory_name,uint_amount) public {}
This is a function named eatHamburgers that takes 2 parameters: a string and a uint. For now the body of the function is empty. Note that we're specifying the function visibility as public. We're also providing instructions about where the _name variable should be stored in memory. This is required for all reference types such as arrays, structs, mappings, and strings.
What is a reference type you ask? Well, there are two ways in which you can pass an argument to a Solidity function:
By value, which means that the Solidity compiler creates a new copy of the parameter's value and passes it to your function. This allows your function to modify the value without worrying that the value of the initial parameter gets changed.
By reference, which means that your function is called with a... reference to the original variable. Thus, if your function changes the value of the variable it receives, the value of the original variable gets changed.
It's convention (but not required) to start function parameter variable names with an underscore (_) in order to differentiate them from global variables.
You would call this function like so:
eatHamburgers("vitalik", 100);
Private / Public functions
In Solidity, functions are public by default. This means anyone (or any other contract) can call your contract's function and execute its code.
Obviously, this isn't always desirable and can make your contract vulnerable to attacks. Thus it's good practice to make all functions private, and then only make public the functions you want to expose to the world.
This means only other functions within our contract will be able to call this function and add to the numbersarray.
As you can see, we use the keyword privateafter the function name.
It's convention to start private function names with an underscore _.
Internal and External functions
In addition to public and private, Solidity has two more types of visibility for functions:
internal
Similar private, except that it's also accessible to contracts that inherit from this contract.
external
Similar to public, except that these functions can ONLY be called outside the contract β they can't be called by other functions inside that contract.
For declaring internal or external functions, the syntax is the same as private and public:
contract Sandwich {uintprivate sandwichesEaten =0;functioneat() internal { sandwichesEaten++; }}contractBLTisSandwich {uintprivate baconSandwichesEaten =0;functioneatWithBacon() publicreturns (stringmemory) { baconSandwichesEaten++;// We can call this here because it's internaleat(); }}
Function Input Parameters
If a function requires an input parameter for the function to be valid (e.g. for an override) but you don't actually use the parameter in the function, it can be commented out.
This getKitty function is the first example we've seen that returns multiple values. Let's look at how to handle them:
functionmultipleReturns() internalreturns(uint a,uint b,uint c) {return (1,2,3);}functionprocessMultipleReturns() external {uint a;uint b;uint c;// This is how you do multiple assignment: (a, b, c) =multipleReturns();}// Or if we only cared about one of the values:functiongetLastReturnValue() external {uint c;// We can just leave the other fields blank: (,,c) =multipleReturns();}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.13;contract Function {// Functions can return multiple values.functionreturnMany()publicpurereturns (uint,bool,uint ) {return (1,true,2); }// Return values can be named.functionnamed()publicpurereturns (uint x,bool b,uint y ) {return (1,true,2); }// Return values can be assigned to their name.// In this case the return statement can be omitted.functionassigned()publicpurereturns (uint x,bool b,uint y ) { x =1; b =true; y =2; }// Use destructuring assignment when calling another// function that returns multiple values.functiondestructuringAssignments()publicpurereturns (uint,bool,uint,uint,uint ) { (uint i,bool b,uint j) =returnMany();// Values can be left out. (uint x,,uint y) = (4,5,6);return (i, b, j, x, y); }// Cannot use map for either input or output// Can use array for inputfunctionarrayInput(uint[] memory_arr) public {}// Can use array for outputuint[] public arr;functionarrayOutput() publicviewreturns (uint[] memory) {return arr; }}