Expressions and Control Structures in Solidity

Reading Time: 3 minutes

Hey Readers! Welcome back to the world of Solidity. In this blog we will see what are the Expressions and Control Structures in Solidity.

Expressions and Control Structures in Solidity is a vast concept that we will see today.

Control Structures

Most of the control structures known from curly-braces languages are available in Solidity:

There are if, else, while, do, for, break, continue, return, with the usual semantics known from C or JavaScript.

Solidity also supports exception handling in the form of try/catch-statements, but only for external function calls and contract creation calls.

Function Calls

Internal Function Calls

Functions of the current contract can be called directly (“internally”). Also recursively, as seen in this nonsensical example:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

// This will report a warning
contract C {
    function example1(uint variable) public pure returns (uint ret) { return variable + example1(); }
    function example2() internal pure returns (uint ret) { return example2(7) + example1(); }
}

Function calls are translated into simple jumps inside the EVM.

This shows that the current memory is not clear, i.e. passing memory references to internally-called functions is very efficient. Only functions of the same contract instance can be called internally.

You should still avoid excessive recursion, as every internal function call uses up at least one stack slot and there are only 1024 slots available.

External Function Calls

Functions can also be called using the this.example1(8); and c.example1(2); notation, where c is a contract instance and example1 is a function belonging to c. Calling the function example1 via either way results in it being called “externally”, using a message call and not directly via jumps. Please note that function calls on this cannot be used in the constructor, as the actual contract has not been created yet.

Functions of other contracts have to be called externally. For an external call, all function arguments have to be copied to memory.

When calling functions of other contracts, you can specify the amount of Wei or gas sent with the call with the special options {value: 10, gas: 10000}. Note that it is discouraged to specify gas values explicitly, since the gas costs of opcodes can change in the future. Any Wei you send to the contract is added to the total balance of that contract:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;

contract InfoFeed {
    function info() public payable returns (uint ret) { return 42; }
}

contract Consumer {
    InfoFeed feed;
    function setFeed(InfoFeed addr) public { feed = addr; }
    function callFeed() public { feed.info{value: 10, gas: 800}(); }
}

You need to use the modifier payable with the info function because otherwise, the value option would not be available.

Due to the fact that the EVM considers a call to a non-existing contract to always succeed, Solidity uses the extcodesize opcode to check that the contract that is about to be called actually exists (it contains code) and causes an exception if it does not. This check is skipped if the return data will be decoded after the call and thus the ABI decoder will catch the case of a non-existing contract.

Note that this check is not performed in case of low-level calls which operate on addresses rather than contract instances.

Function calls also cause exceptions if the called contract itself throws an exception or goes out of gas.

Named Calls and Anonymous Function Parameters

Function call arguments can be given by name, in any order, if they are enclosed in { } as can be seen in the following example. The argument list has to coincide by name with the list of parameters from the function declaration, but can be in arbitrary order.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;

contract C {
    mapping(uint => uint) data;

    function f() public {
        set({value: 2, key: 3});
    }

    function set(uint key, uint value) public {
        data[key] = value;
    }

}

Omitted Function Parameter Names

The names of unused parameters (especially return parameters) can be omitted. Those parameters will still be present on the stack, but they are inaccessible.

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

contract C {
    // omitted name for parameter
    function func(uint var1, uint) public pure returns(uint) {
        return var1;
    }
}

Thank You for reading. These were few concepts with example code about the Expressions and Control Structures in Solidity.


If you want to read more content like this?  Subscribe to Rust Times Newsletter and receive insights and latest updates, bi-weekly, straight into your inbox. Subscribe to Rust Times Newsletter: https://bit.ly/2Vdlld7.


Knoldus-blog-footer-image

Written by 

Ayushi is a Software Developer having more than 1.5 year of experience in RUST. Her practice area is Rust and Go. She loves to solve daily coding challenges.