Back to glossary

Solidity Function

Table of Contents

What are Solidity functions?

Solidity functions are reusable blocks of code in a smart contract that performs a specific task or set of tasks. Functions in Solidity, can modify contract states, process transactions, and interact with other contracts.

How are functions declared in Solidity?

A function declaration is defined using the function keyword followed by the function name, parameters (if any), visibility specifier, return type (optional), and function body. For example:

contract Calculations {

    function addNumbers(uint a, uint b) public pure returns (uint) {
        return a + b;
    }

}

In the code block above:

  • addNumbers is the function name.
  • uint a, uint b are the named parameters of type uint (unsigned integer).
  • public keyword is the visibility specifier that makes it accessible from outside of the contract.
  • pure is the function type, indicating the function does not modify the blockchain state.
  • returns (uint) specifies the function returns a uint value.

Attributes of Solidity functions

Solidity functions can be defined inside or outside a contract. 

  • Functions defined outside a contract: are called “free functions” and must have implicit internal visibility. Free functions are utility functions that can be used by many contracts and do not have direct access to the variable this, storage variables, and functions not in their scope. 
  • Functions defined inside a contract: have access to the contract’s state variables, functions, and events. They can modify contract storage, access this, be public, private, or have other levels of visibility depending on the intended access control.

Named and Unnamed Parameters in Solidity Functions

Solidity functions can have both named and unnamed parameters to enhance code readability. Named parameters are explicitly labeled with variable names in the function definition, while unnamed parameters are used when the parameter name is not needed within the function body.

// named parameter 
function calculateSum(uint256 a, uint256 b) public {
    sum = a + b;
}

// unnamed parameter
function increment(uint256) public {
 // function body
}

Solidity Functions Return Values

Functions can return multiple values using tuples. These values can either be unnamed or named in the return statement.

function getMultipleValues() public view returns (uint256 value1, string memory value2) {
    // function body
}

Functions can return standard variables like integers, strings, and addresses. Additionally, return statements can include named returns, allowing values to be named for improved readability:

  • Named returns: The values returned are declared with names directly in the function's signature.
  • Unnamed returns: Values are returned without explicit names, typically when the result is immediately consumed without the need for clarity.

Recursion in Solidity Functions

Solidity functions can be recursive. They allow for calls within themselves or within other functions in the same contract. They are useful for repetitive or iterative computations but should be used carefully to avoid stack overflow errors due to gas consumption.

Types of Solidity functions

Solidity functions include state-changing, non-state-changing functions (such as pure and view), payable, and receive and fallback functions.

State changing functions

State changing functions alter the information stored on the blockchain and require a signature and gas fee. For example, updating a variable or transferring a token from one address to another. 

address public balance = 10 token;
 
function updateBalance(uint256 _newBalance) public {
    balance = _newBalance;
}

Non-state changing functions 

Non-state changing functions do not change the blockchain state and are important for minimizing gas costs for functions that are called frequently. Two major non-state changing functions are pure and view.

view functions read the contract's state but do not modify it, and are generally used to retrieve data. For example, fetching information such as the balance of an address.

// View function
function getBalance() public view returns (uint256) {
    return address(this).balance;;
}

pure functions do not read or modify state variables and return values based on the parameters supplied to the function or the local variables existing in it. They are often used in libraries to perform calculations or utility operations.

// Pure function
function add(uint256 a, uint256 b) public pure returns (uint256) {
    return a + b;
}

Payable modifier

When a function is marked payable in solidity it allows the function to receive the native network cryptocurrency (for example ETH on the Ethereum chain, or POL on the Polygon chain). If you try to send a token to a function without this modifier, the transaction will be rejected and fail.

Receive and fallback solidity functions

Two special Solidity functions are fallback and receive. They are executed when a contract is sent a token without specifying a function or when sent data does not match the identifier of an existing function in the smart contract.

Receive function: It allows a contract to accept tokens and is automatically called when a contract receives a token with empty calldata. It is used for handling unexpected token transactions or recovering funds from failed function calls. For example, if a contract receives a token with no data attached to the transaction, it must be marked external and payable and does not accept arguments.

receive() external payable {
    // Logic for receiving token
}

Fallback function: functions marked as payable are called when sent data does not match any function specified in the smart contract or when a contract is sent a token without specifying a function.

fallback() external payable {
    // Fallback logic
}

Function visibility

Function visibility controls which contract or dApp can call a function. There are three types of callers: the main contract, a contract derived from the main contract, and an external caller. Function visibility is divided into four types: public, private, external, and internal.

Public functions can be accessed and called from anywhere within the contract, from derived contracts, and from other contracts.

function publicFunc() public pure returns (string memory) {
    return "This is a public function";
}

Private functions can only be called by functions within the same contract. This prevents external calls because the function is not exposed outside the contract. For example, calculating internal fees or updating sensitive contract state.

contract Example {
    uint private fee;

    function setFee(uint _fee) public {
        updateFee(_fee); // Calls the private function
    }

    // Private function to update the fee, only callable inside this contract
    function updateFee(uint _fee) private {
        fee = _fee;
    }
}

External functions can only be called externally from other contracts or dApps. It cannot be called internally from within the contract.

function externalFunc() external pure returns (string memory) {
    return "This is an external function";
}

Internal functions can only be called within the same contract or derived contracts. This is useful for sharing functionality across parent and child contracts while preventing external access.

contract ParentContract {
    uint internal storedData;

    function updateData(uint _data) internal {
        storedData = _data;
    }
}

contract ChildContract is ParentContract {
    function modifyData(uint _newData) public {
        updateData(_newData);  
    }
}

Function modifier

Modifiers are used to change the behavior of functions in a declarative way. For example, checking a condition before executing the function. Or, for access control to ensure only the contract owner can execute a function.

modifier onlyOwner() {
    require(msg.sender == owner, "Not the contract owner");
    _;
}

function withdraw() public onlyOwner {
    payable(msg.sender).transfer(address(this).balance);
}

In this example, the onlyOwner modifier checks if the caller is the contract owner before allowing them to withdraw funds, and _; indicates where the function will be inserted. Here, the check is executed before allowing withdrawal of funds.

Best practices for solidity functions

  1. Use clear, descriptive names
  2. Implement proper error handling and input validation
  3. Use modifiers for security and code readability
  4. Optimize gas usage 
  5. Follow consistent coding standards
  6. Regularly update and audit your smart contracts

Related Terms

No items found.