Solidity Function Constructors – A Helpful Simplified Guide with Video

In this article, we’ll learn about function constructors, a Solidity language feature enabling us to execute a function during smart contract creation.

It’s part of our long-standing tradition to make this (and other) articles a faithful companion or a supplement to the official Solidity documentation. We’ll base this article on the original Solidity programming language content.

Conceptual Overview

A constructor is a Solidity language feature that makes it possible to attach a specific behavior, i.e., a function, to the beginning of the smart contract lifecycle. It is executed only once – when a contract’s instance is created. A constructor is the right place to define the contract initialization code.

The initialization cycle starts with the state variables: in case of an inline initialization, they are set to their explicitly specified values. Otherwise, the state variables are set to their type-determined default value when inline initialization is omitted. The next step of the initialization cycle is the execution of the constructor code.

After the constructor execution concludes, the final code of the contract is ready and deployed to the blockchain. This is a good place for us to discuss the cost of the contract deployment, which is proportional to the length of the code.

When we say “code”, we imply all the functions that make up the public interface, i.e., functions whose visibility modifiers are public or external.

Besides, all the functions can be reached via function calls through the public interface functions. In contrast, the contract cost does not include the constructor code or the functions only called from the constructor and whose visibility is set to internal.

πŸ‘©β€πŸ’» Recommended: Solidity Function Calls – Internal and External

Default Constructor

As with most of our examples in previous articles, if we omit the constructor, the compiler will imply there’s a default constructor, which has no arguments and no body: constructor() {}, as showcased in this simple example:

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

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

contract A {

    // A default constructor can be omitted.
    constructor() {}
}

The sole purpose of a default constructor is to initialize the state variables with their default, type-dependant values.

πŸ’‘ Note: Don’t forget to include the pragma directive before trying each of the following examples; I’m deliberately omitting it to avoid unnecessary code duplication.

Regular Constructor

First, we’ll take a look at a simplified example of a constructor that initializes the state variables to fixed values through a process called inline initialization:

contract A {
    uint public a;

    constructor() {
        a = 5;
    }
}

In this example, our state variable A is initialized to a fixed value of 5. Of course, this approach is excessive since we could have gotten exactly the same effect simply by doing the following:

contract A {
    uint public a = 6;
}

However, these two examples are hard-coded and don’t demonstrate the real usefulness of constructors, but I showed them for the sake of completeness and better understanding. The following example will start to unveil the true versatility and purpose behind using constructors:

contract A {
    uint public a;

    constructor(uint a_) {
        a = a_;
    }
}

contract B {
    A contract_A = new A(22);
    uint public a = contract_A.a();
}

Although more complex, this example shows how to declare a constructor that takes an argument via its parameter uint _a. This way, we can dynamically instantiate our contract, and that’s where the true power of parametrized constructors lies.

First, we declared contract A with a parametrized constructor. Then, we declared a new contract B in which we created an instance of contract A called contract_A by passing it argument 22. Finally, we assigned the value of the state variable contract_A.a to the state variable b by calling its getter function to confirm that contract_A is dynamically instantiated to the value of the given argument.

An even nicer, elegant example with the same effect can be achieved simply by deriving contract B from contract A by giving it an argument:

contract A {
    uint public a;

    constructor(uint a_) {
        a = a_;
    }
}

contract B is A(22) {
}

Conclusion

In this article, we learned about contract constructors.

First, we made a conceptual overview of a constructor in Solidity.

Second, we explained what a default constructor is.

Third, we showed how regular constructors can be declared and used through several illustrative, simple examples.

What’s Next?

This tutorial is part of our extended Solidity documentation with videos and more accessible examples and explanations. You can navigate the series here (all links open in a new tab):