Day 10. Basic Syntax of Solidity – Functions & Modifiers –

In programming, a function is a block of code that encapsulates a specific task or operation. By using functions, code reusability and maintainability are enhanced, enabling efficient programming.

TOC

Functions

A function in a smart contract executes specific actions or processes. Functions are defined as follows: they take arguments (inputs), perform some processing, and return an output. Additionally, as we will discuss later, modifiers can be added to specify the characteristics of a function.

Solidity
function functionName(<arguments>) <modifier> returns (<returnType>) {
    <process>
    ...
    return returnValue;
}

An actual example of a function is as follows. ‘addressToPerson’, mentioned on day 9, is a mapping that links an address type to a Person type. Here, we are returning a uint256 type balance. The modifiers ‘public’ and ‘view’ used here add specific characteristics to the function.

Solidity
contract PersonStorage {
  ...
  function getBalanceOf(address userAddress) public view returns (uint256) {
    uint256 balance = addressToPerson[userAddress].balance;
    return balance;
  }
  ...
}

Modifiers

Modifiers are descriptions that provide additional functionality or behavior to elements like functions or variables. Below are some common modifiers used with functions or variables.

Visibility Modifiers

Visibility modifiers control the access scope of functions or variables.

  • public: Accessible both from inside and outside the contract (including other contracts and GUIs like Remix).
  • private: Accessible only from within the contract where the function or variable is defined.
  • internal: Accessible only from within the contract where it is defined or its derived contracts.
  • external: Exclusively for external calls and accessible only from outside the contract.

The previously mentioned ‘getBalanceOf’ function, with the public modifier, can be called from outside the contract. For example, public is used when you want to check the result of a function execution from the GUI in Remix.

State Modifiers

State modifiers are a type of modifier that specifies how a function affects the state of the smart contract.

  • view: Indicates that the function does not change the state of the smart contract, i.e., it does not modify the values of variables defined within the smart contract. Functions that do not change the state tend to have lower gas costs.
  • pure: Like view, it indicates that the function does not change the state of the smart contract and additionally cannot reference external data (variables within the smart contract). Used for pure mathematical operations or calculations. Functions that do not change the state tend to have lower gas costs.
  • payable: Indicates that the function allows the receipt of Ether. Explicitly specifying payable is required for operations involving the transfer of Ether, such as sending and receiving currency. The ‘getBalanceOf’ function mentioned earlier is suitable for the view modifier as it references but does not change any variables in the smart contract.

An example of payable is shown next. In this example, the ‘deposit’ function has the payable modifier. This function records the person (msg.sender) who called the function and the amount of Ether sent (msg.value) in the ‘balances’ mapping variable.

Solidity
mapping(address => uint) balances;

function deposit() payable external {
    balances[msg.sender] += msg.value;
}

‘msg.sender’ and ‘msg.value’ are special variables with the following meanings:

  • msg.sender: The address of the person or contract that called the ‘deposit’ function.
  • msg.value: The amount of Ether sent when calling the ‘deposit’ function.

An example of calling the ‘deposit’ function in Remix is as follows. Enter the amount of Ether to be sent in the ‘Value’ field and press the ‘deposit’ button to call the function from the external source (Remix). When the function is called, a transaction is issued that calls the ‘deposit’ function, including the ‘msg.sender’ address (0x5B3…) and ‘msg.value’ of 1000000000000000000 Wei (1 ETH).

Function Modifiers

Modifiers are used to add specific actions or behaviors to functions. They enable the definition of common processes between functions, enhancing their reusability.

In the following example, a modifier named ‘onlyOwner’ is defined, and it is used with the function ‘changeOwner’. This ensures that at the beginning of ‘changeOwner’, it checks if the person calling the function is the current owner. If not the owner, an error message is displayed, and the function does not execute (this action of stopping the transaction is called ‘revert’). If the caller is the owner, the address specified in the argument becomes the new owner.

Solidity
contract PersonStorage {
  address public owner = 0x551af3f6A226a62BCb27f08B42401bd5629f2E44;
  ...
  modifier onlyOwner() {
      // Error message means "Only the contract owner can call this function."
      require(msg.sender == owner, "Only contract owner can call this function");
      _; // Placeholder (where the function is executed)
  }

  function changeOwner(address newOwner) public onlyOwner {
      owner = newOwner;
  }
}

Other Modifiers

Constants are variables that always represent a fixed value. There are two modifiers for defining constants: ‘constant’ and ‘immutable’.

  • constant: Once set, its value cannot be changed and will always have the same value at runtime. The value must be set when the variable is defined.
  • immutable: Similar to constant, but its value must be set either when the variable is defined or within a special function called ‘constructor’, which is called during the contract’s initialization.

In the next example, the constant variable ‘FEE’ and the immutable variable ‘i_owner’ are defined. ‘FEE’ is set as 0.1 ETH and cannot be changed. ‘i_owner’ is for setting the owner’s address, but unlike constant, its value is set only once during the contract’s initialization (deployment) in the constructor function. The contract deployer’s address is set as ‘i_owner’.

As a convention, constant variables are often defined in uppercase, and immutable variables start with ‘i_’.

Solidity
contract PersonStorage {
  uint256 public constant FEE = 1e17; // 0.1ETH
  address public immutable i_owner;
  ...
  constructor() {
    i_owner = msg.sender;
  }
}
```"
Let's share this post !

Author of this article

After joining IBM in 2004, the author gained extensive experience in developing and maintaining distributed systems, primarily web-based, as an engineer and PM. Later, he founded his own company, designing and developing mobile applications and backend services. He is currently leading a Tech team at a venture company specializing in robo-advisory.

Comments

To comment

CAPTCHA


TOC