October 9, 2022

Multiple Inheritance in Solidity

There are lots of documentation about C3 and so on, but I feel that example is better. Jump with me, it won't take long.

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

abstract contract A {
    event E(int);

    function Hello() external virtual;
    function Hello2() external virtual;
}

contract B is A {
    function Hello() public override virtual {
        emit E(2);
    }
    function Hello2() public override virtual {
        emit E(2);
    }
}

contract C is A {
    function Hello() public override virtual {
        emit E(3);
    }
    function Hello2() public override virtual {
        emit E(3);
    }
}

contract D is B, C {
    function Hello() public override(B, C) {
        super.Hello();
    }
    function Hello2() public override(C, B) {
        super.Hello2();
    }
}

contract D2 is C, B {
    function Hello() public override(B, C) {
        super.Hello();
    }
    function Hello2() public override(C, B) {
        super.Hello2();
    }
}

contract D3 is C, B {
    function Hello() public override(B, C) {
        B.Hello();
        C.Hello();
    }
    function Hello2() public override(C, B) {
        C.Hello2();
        B.Hello2();
    }
}

And results (printing events):

D.Hello
["0x0000000000000000000000000000000000000000000000000000000000000003"] 
D.Hello2
["0x0000000000000000000000000000000000000000000000000000000000000003"] 
D2.Hello
["0x0000000000000000000000000000000000000000000000000000000000000002"] 
D2.Hello2
["0x0000000000000000000000000000000000000000000000000000000000000002"] 
D3.Hello
["0x0000000000000000000000000000000000000000000000000000000000000002","0x0000000000000000000000000000000000000000000000000000000000000003"] 
D3.Hello2
["0x0000000000000000000000000000000000000000000000000000000000000003","0x0000000000000000000000000000000000000000000000000000000000000002"]

If you are familiar with Python, this is confusing, as in Python super() traverses the whole hierarcy:

class A:
    def Hello(self):
        print("A")

class B(A):
    def Hello(self):
        print("B")
        super().Hello()

class C(A):
    def Hello(self):
        print("C")
        super().Hello()

class D(B,C):
    def Hello(self):
        print("D")
        super().Hello()

class D2(C,B):
    def Hello(self):
        print("D2")
        super().Hello()

D().Hello()
D2().Hello()

Running...

D
B
C
A

D2
C
B
A