10

I'm reading the section on inherited constructors on the documentation here.

The example given confuses me than understanding the concept, and it doesn't explain the most important part, the execution order.

To summarize the documentation, it says in the following example:

pragma solidity ^0.4.0;

contract Base {
  uint x;
  function Base(uint _x) { x = _x; }
}


contract Derived1 is Base(7) {
  function Derived1(uint _y) {
  }
}

contract Derived2 is Base{
  function Derived2(uint _y) Base(_y * _y) {
  }
}

Derived1 inherits Base(7) constructor, and Derived2 uses a modifier-like syntax of Base(_y * _y).

But what it DOESN'T explain is how they are actually executed. Let's take an example

contract Base {
  public uint x;
  function Base(uint _x) { x = _x; }
}


contract Derived1 is Base(7) {
  function Derived1(uint _y) {
    x = _y;
  }
}

contract Derived2 is Base {
  function Derived2(uint _y) Base(_y * _y) {
    x = _y;
  }
}

does the x = _y in each inheritance get executed BEFORE the base constructor? or after?

Normally in any object oriented oriented programming you use notations like super() to explicitly state how the parent constructor will be executed.

In case of objective-c

- (void) init {
  [super init];
  // do something
}

and

- (void) init {
  // do something
  [super init];
}

make a huge difference since the execution order is different. And the //do something part may even utilize the result from [super init].

So how does this thing work in Solidity? If you can, please share the source for the explanation as well. I can't find this on the documentation so I don't know where else I can find this.

3
  • Also please don't say it's a duplicate and use an example that points to how to use constructors in inheritance. I already know the syntax. I am explicitly asking about the execution order, and where this is documented officially. For example I have already read this answer ethereum.stackexchange.com/questions/16318/… but this doesn't explain the order which is the core of this question.
    – Vlad
    Oct 31, 2017 at 16:01
  • In your code, in the contracts Derived1 and Derived2, did you mean the function names to be Derived1 and Derived2, respectively, so that they are constructors, instead of Derived in both? Oct 31, 2017 at 16:46
  • @AjoyBhatia thanks for pointing that out! Just fixed it.
    – Vlad
    Oct 31, 2017 at 17:12

2 Answers 2

3

Current Solidity docs provide the answer in this paragraph: https://docs.soliditylang.org/en/v0.8.13/contracts.html#multiple-inheritance-and-linearization

Basically: Solidity guarantees that all the base classes' constructors will be called before a derived class constructor. And the derived class constructor cannot change the order in which base classes constructors are called by Solidity.

But this is a bit complicated as Solidity has to deal with multiple inheritance. As explained in the docs, the inheritance graph for the derived class is linearized using C3 linearization, which yields an ordered list of classes where each derived class appears after all its base classes. The constructors are called in the order of the list. When you have more than one base class, the order that they appear in the list will be influenced by the order in which they are listed in the inheritance list (ie after the is).

Quoting from the documentation:

One area where inheritance linearization is especially important and perhaps not as clear is when there are multiple constructors in the inheritance hierarchy. The constructors will always be executed in the linearized order, regardless of the order in which their arguments are provided in the inheriting contract’s constructor. For example:

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

contract Base1 {
    constructor() {}
}

contract Base2 {
    constructor() {}
}

// Constructors are executed in the following order:
//  1 - Base1
//  2 - Base2
//  3 - Derived1
contract Derived1 is Base1, Base2 {
    constructor() Base1() Base2() {}
}

// Constructors are executed in the following order:
//  1 - Base2
//  2 - Base1
//  3 - Derived2
contract Derived2 is Base2, Base1 {
    constructor() Base2() Base1() {}
}

// Constructors are still executed in the following order:
//  1 - Base2
//  2 - Base1
//  3 - Derived3
contract Derived3 is Base2, Base1 {
    constructor() Base1() Base2() {}
}
2

I couldn't find a official doc to explain this. But when referring to the code, the flow of the program we can assume that constructor of the Base is called before the Derived constructor.

In the first one Derived1 is Base(7) the Base(7) syntax has the look of the constructor with the value 7 being passed and probably be calling before going to the Derived1 constructor when the declared order is considered.

In the second one since the docs says,

the way a modifier would be invoked

and since always the modifiers are executed before going into the function body we can come to the conclusion that Base(7) is executed first.

With the above assumptions I tried the following code in Remix with _y=10 at contract creation. The getX function in both contracts returned a value of 10 but not 7 in Derived1 or 100 which is (_y*_y) in Derived2. That means Base constructor is executed first and value of x is overwritten to 10 by x = _y; in the body of Derived constructors. I think this proves that the Base constructor is expected first.

pragma solidity ^0.4.0;

contract Base {
  uint x;
  function Base(uint _x) { x = _x; }
}


contract Derived1 is Base(7) {
  function Derived1(uint _y) {
      x = _y;
  }

  function getX() constant returns(uint){
      return x;
  }
}

contract Derived2 is Base {
  function Derived2(uint _y) Base(_y * _y) {
      x = _y;
  }

  function getX() constant returns(uint){
      return x;
  }

}

(if you don't have x = _y in Derived constructors returned values are 7 and 100)

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.