Solidity Interface – Smart Contract Inheriting a Contract to Supply Part of Interface

solidity

Given a smart contract setup where there is an Interface object that defines multiple different functions that a new contract wishes to adhere to, and it wants to inherit some functionality to define some of that logic, I expected a structure like this to work:

pragma solidity ^0.8.9;

interface A {
    function foo() external returns (uint256);
    function bar() external returns (uint256);
}

contract B {
    function foo() public returns (uint256) {
        return 1;
    }
}

contract MyContract is A, B {
    function bar() public returns (uint256) {
        return 2;
    }
}

The Solidity compiler fails to compile this, giving the error "TypeError: Derived contract must override function "foo". Two or more base classes define function with same name and parameter types."

It finds the foo reference in both the A interface and the B contract definition and seems to be unable to merge them, even though A is an interface, and its definition of foo is just a definition, not an implementation.

The only way I've found around this is to add a function to MyContract like

function foo() public override(A, B) returns (uint256) {
    return B.foo();
}

Is this a bug in the compiler (it's not ignoring function definitions that aren't implemented), or is there a more elegant way to combine logic like this?

Best Answer

Looking through past issue requests on the Solidity GitHub, it appears this situation falls into the same space as this request, and the answer is the Solidity compiler forces that additional declaration on the child contract as a design choice; forcing the developer to indicate they are aware that there are two methods with the same name, and to explicitly declare they're not just named the same, but are functionally/conceptually the same.

The other option, if the developer has control of the definition of B, is to do:

pragma solidity ^0.8.9;

interface A {
    function foo() external returns (uint256);
    function bar() external returns (uint256);
}

abstract contract B is A {
    function foo() public returns (uint256) {
        return 1;
    }
}

contract MyContract is B {
    function bar() public override returns (uint256) {
        return 2;
    }
}

Namely, change B to not be a Contract but an Abstract Contract, explicitly defining it as a partial implementation of interface A, and have MyContract only inherit from B.

Related Topic