[Ethereum] Providing base contracts’ constructor arguments

contract-designinheritancesolidity

I'm a bit puzzled about multiple inheritance and providing arguments for different constructors. Solidity documentation has long explanations about this (http://solidity.readthedocs.io/en/develop/contracts.html#arguments-for-base-constructors) but (in my opinion) not enough information about base contracts' arguments. It states:

If the base constructors have arguments, derived contracts need to specify all of them

How does this exactly work when there is a complicated inheritance chart? An example:

pragma solidity ^0.4.0;

contract A {
    constructor(uint paramA) public {

    }
}

contract B is A {
    constructor(address paramB) public {

    }
}

contract C is A {
    constructor(string paramC) public {

    }
}

contract D is B, C {
    constructor(uint paramForA, address paramForB, string paramForC) public // stuff here to call A, B and C constructors with non-static parameters
    {

    }
}

How should contract D specify its constructor arguments for contracts A B and C to provide all required parameters and in what order? Is there only one correct order?

Best Answer

In Solidity you specify base constructor arguments in two ways (according to http://solidity.readthedocs.io/en/latest/contracts.html#arguments-for-base-constructors):

The first way to do it is more convenient if the constructor argument is a constant and defines the behaviour of the contract or describes it. The second way has to be used if the constructor arguments of the base depend on those of the derived contract. Arguments have to be given either in the inheritance list or in modifier-style in the derived constuctor. Specifying arguments in both places is an error.

Your inheritance structure is as follows: D->C->B->A.

If we change the order a little bit (just to be sure that constructor executions are different than the code sequence) and add some logging we get:

contract A {
    constructor(uint paramA) public {
        log0(bytes32(0x00000000));  
    }
}


contract C is A(0) {
    constructor(string paramC) public {
        log0(bytes32(0x00000002));  
    }
}

contract B is A{
    constructor(address paramB) public {
      log0(bytes32(0x00000001));  
    }
}

contract D is B, C {
    constructor(uint paramForA, address paramForB, string paramForC) public  C(paramForC) B(paramForB)// stuff here to call A, B and C constructors with non-static parameters
    {
        log0(bytes32(0x00000003));  
    }
}

You get the following execution od constructors: A->B->C->D

Note that if you change the order of inheritance and rewrite D as follows:

contract D is C, B {
    constructor(uint paramForA, address paramForB, string paramForC) public  C(paramForC) B(paramForB)// stuff here to call A, B and C constructors with non-static parameters
    {
        log0(bytes32(0x00000003));  
    }
}

You will get different order of execution A->C->B->D

So the order does matter.

EDIT1: As the above was not exactly to the point below I try to address question: "How should contract D specify its constructor arguments for contracts A B and C to provide all required parameters and in what order? Is there only one correct order?"directly.

You can assign parameters to parent contract constructors in two ways:

1. Directly in the declaration of inheritance:

contract D is B('0x0b'), C('0x0c') {
    constructor(uint paramForA, address paramForB, string paramForC) public 
    {
    }
}

where 0x0b and 0x0a are address literals.

2. Via assigning them using syntax similar to Solidity modifiers if you want to use constructor D arguments:

contract D is B, C {
    constructor(uint paramForA, address paramForB, string paramForC) public  C(paramForC) B(paramForB) {}
}

There is not other way to initialize parent contract constructors that I'm aware of. If you would like to initialize state variables of parent contract you can make it within the D constructor. Those state variables has to be either public or internal in the parent contract. Hope this helps.

Related Topic