2

I have a function in a base contract that could have the state mutability modifier "pure" because it always returns true:

    BaseContract {
        function x(bytes memory) 
            public
            view
            returns(bool) 
        {
            return true
        }
    }

However, this function is usually overridden in derived contracts, like so:

DerivedContract is Base {
    function x (bytes memory payload) 
        public 
        view 
        returns(bool) 
    {
        // do some non-pure stuff
        // return true OR false
    }
}

My question regarding how to silence this compiler warning is rooted in deeper questions:

  1. Does function overriding in Solidity still work, even if the to-be-overidden function has a non-identical state mutability modifier?
  2. Therefore, can I change the state-mutability modifier of the base function to pure, and still have this function overridden, or will the two dissimilar state mutabilities (view vs. pure), all else being identical, result in some sort of function overloading?
  3. If overriding a function with a dissimilar state mutability does not work, how can I silence the aforementioned compiler warning?

Thanks for your help!

2 Answers2

2

I found that OpenZeppelin seems to silence such compiler warnings about state mutability in this way:

function _msgData() internal view returns (bytes memory) {
    this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
    return msg.data;
}

This snippet is from there Context.sol contract.

1

I believe that all of this can be solved with a single keyword - interface.

For example:

pragma solidity 0.4.26;

interface IBaseContract {
    function func(uint _x) external view returns (bool);
}

contract BaseContract is IBaseContract {
    function func(uint _x) external view returns (bool) {
        return _x == 1;
    }
}

contract DerivedContract is BaseContract {
    uint public x;
    function func(uint _x) external view returns (bool) {
        return _x == x;
    }
}

And the compilation warning is gone!

The only problem that I can think of here, is that you cannot declare public functions in an interface.

So for once, you cannot override your public variable getter functions, since those are... well, public.

But that can be solved by explicitly declaring an external getter function with a slightly different name (e.g., getVal instead of val).

Of course, you don't have to do this for every public variable in your contract, but just for those which are used by other contracts.

Second, if one of your functions must be public (because it is used both internally in the contract and externally by other contracts or from an off-chain script), then - again - you cannot delcare it in the interface.

The solution in this case is simply to split it into an external function and an internal or private function.

Note that with this approach, the only public function remaining in each contract would be the constructor itself, which can be either public or internal.

goodvibration
  • 26,003
  • 5
  • 46
  • 86
  • Hi, and thank you for helping @goodvibrtaion. I have decided just to ignore the compiler warning. The only other 'clean' way for me to go about this, without introducing more code from manually written getters and internal vs external functions, would be to write an interface, from which to inherit, just for this one function. This seems a little dirty. What do you think? Also, can you explain why the state mutability warning is bypassed, if you inherit the function from an interface, please? – Luis Schliesske Oct 06 '19 at 08:38
  • also, I cannot upvote your answer, since I am a newbie here and dont have the reputation points to do so. – Luis Schliesske Oct 06 '19 at 08:46
  • @LuisSchliesske: No worries about the vote. I cannot really explain why the compilation warning is resolved when changing from contract to interface and/or when changing the function from public to external. Perhaps the compiler implementation is such that a contract dictates tight restrictions (e.g., function should be view) and an interface dictates weaker restrictions (e.g., function can be view or "lower"). Perhaps this is even dictated by the Solidity language standard, in which case, you could find it in the official documentation. – goodvibration Oct 06 '19 at 09:11
  • But regardless of all of this, IMO, interfaces are useful not because they solve (or workaround) this specific compilation warning, but because they allow for a more clean and more transparent system design, which makes it easier for users to read your code and distinguish between API and internal functionality. Also, IMO, public variable getter functions, are more of a curse than a bless (again, because they are less transparent for the user). So the fact that they cannot be declared in your interface is not much of a downside. – goodvibration Oct 06 '19 at 09:11
  • Explaining the "make it easier to... distinguish between API and internal functionality" part: this is because the only thing that you are allowed to do in an interface is declaring external functions. No public functions (which can be called internally) are allowed, no variable declaration is allowed, and no function implementation is allowed. Just recalled - enum declaration is not yet supported (at least in Solc v0.4.x). That one definitely is a downside. – goodvibration Oct 06 '19 at 09:18
  • Hi again @goodvibration! thanks for your take on this. I understand all of your points and tend to agree with them. However, the trade-off between the API vs. internal functionality clarity afforded by this interface design approach is that you need to add so much more code. And usually my prime and overriding design principle is: the less code, the better. So I am not 100% sold on it yet. I guess I'll first have to wait for feedback from other devs trying to work with my code, to make that trade-off feasibility judgment. – Luis Schliesske Oct 07 '19 at 08:12
  • OpenZeppelin seems to do this to bypass the compiler warning - (I found it here: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/GSN/Context.sol)

    function _msgData() internal view returns (bytes memory) { // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 this; return msg.data; }

    – Luis Schliesske Oct 09 '19 at 16:32
  • @LuisSchliesske: That's a very useful piece of information! Thank you! May I suggest that you post it as an answer to your own question? – goodvibration Oct 09 '19 at 17:02
  • yep! please upvote my answer so I can finally get some reputation points going :D. – Luis Schliesske Oct 09 '19 at 17:06
  • @LuisSchliesske: Done (for all of them). – goodvibration Oct 09 '19 at 17:12
  • Thanks! I wanted to send you a pm bit doesnt work apparently. I just posted a new question, in case you wanna jump on it, would be great!: https://ethereum.stackexchange.com/questions/76597/value-of-msg-sender-in-call-to-inherited-external-function. – Luis Schliesske Oct 09 '19 at 17:15