// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
/* Graph of inheritance
A
/ \\
B C
/ \\ /
F D,E
*/
contract A {
function foo() public pure virtual returns (string memory) {
return "A";
}
}
// Contracts inherit other contracts by using the keyword 'is'.
contract B is A {
// Override A.foo()
function foo() public pure virtual override returns (string memory) {
return "B";
}
}
contract C is A {
// Override A.foo()
function foo() public pure virtual override returns (string memory) {
return "C";
}
}
// Contracts can inherit from multiple parent contracts.
// When a function is called that is defined multiple times in
// different contracts, parent contracts are searched from
// right to left, and in a depth-first manner.
contract D is B, C {
// D.foo() returns "C"
// since C is the right most parent contract with function foo()
function foo() public pure override(B, C) returns (string memory) {
return super.foo();
}
}
contract E is C, B {
// E.foo() returns "B"
// since B is the right most parent contract with function foo()
function foo() public pure override(C, B) returns (string memory) {
return super.foo();
}
}
// Inheritance must be ordered from "most base-like" to "most derived".
// Swapping the order of A and B will throw a compilation error.
contract F is A, B {
function foo() public pure override(A, B) returns (string memory) {
return super.foo();
}
}
contract F return "B" regardless of override(A, B) or override(B, A)?Prompt (First Prompt): You provided a Solidity contract with the inheritance graph:
A
/ \\\\
B C
/ \\\\ /
F D,E
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
contract A {
function foo() public pure virtual returns (string memory) {
return "A";
}
}
contract B is A {
function foo() public pure virtual override returns (string memory) {
return "B";
}
}
contract C is A {
function foo() public pure virtual override returns (string memory) {
return "C";
}
}
contract D is B, C {
function foo() public pure override(B, C) returns (string memory) {
return super.foo();
}
}
contract E is C, B {
function foo() public pure override(C, B) returns (string memory) {
return super.foo();
}
}
contract F is A, B {
function foo() public pure override(A, B) returns (string memory) {
return super.foo();
}
}
You asked why F.foo() returns "B" whether the override is override(A, B) or override(B, A).
Answer:
override(A, B) or override(B, A) specifier only indicates which parent contracts’ foo() functions are being overridden. It does not affect the resolution of super.foo().super.foo() resolves to the foo() function of the first parent in the C3 linearization that defines foo().contract F is A, B:
[F, B, A].
F.B (second parent, inherits from A).A (first parent, but also a base of B).super.foo() is called, Solidity searches [F, B, A]:
F calls super.foo(), so skip F.B defines foo() (returns "B").A defines foo() (returns "A"), but B comes first.super.foo() resolves to B.foo(), returning "B".override(A, B) to override(B, A) doesn’t change the linearization ([F, B, A]), so the output remains "B".F is A, B is valid because A is the base contract, and B inherits from A, satisfying the "most base-like to most derived" rule.contract F is A, B {
function foo() public pure override(A, B) returns (string memory) {
return super.foo(); // Returns "B"
}
}
[F, B, A] → super.foo() → B.foo() → "B".contract F is B, A cause a compilation error?Prompt:
You modified contract F to:
contract F is B, A {
function foo() public pure override(A, B) returns (string memory) {
return super.foo();
}
}
And asked why this causes a compilation error.