1

Based on Shawn's answer,

super._mint calls addTokenTo from the top level implementation (ERC721Token).

How does this work?

  1. super._mint calls _mint from ERC721BasicToken
  2. reads line addTokenTo
  3. calls top level addTokenTo from ERC721Token
  4. reads line super.addTokenTo(_to, _tokenId);
  5. executes addTokenTo from ERC721BasicToken
  6. comes back to addTokenTo in ERC721Token and executes the rest (ownedTokens)

Is this flow correct? and how come #2 doesn't call addTokenTo in ERC721BasicToken and calls top level addTokenTo?

3

The solidity compiler does some "magic" when you include multiple files and do contract inheritance as is done in the ERC721 token contract. Ultimately it flattens the contract files into a single file and treats the inheritance and overridden functions in a deterministic way:

https://solidity.readthedocs.io/en/v0.4.21/contracts.html#inheritance

All function calls are virtual, which means that the most derived function is called, except when the contract name is explicitly given.

When a contract inherits from multiple contracts, only a single contract is created on the blockchain, and the code from all the base contracts is copied into the created contract.

Here is what "most derived" means; take a look at the example from the docs about Base1 and Base2.


Ultimately, the top level contract's function implementation will ALWAYS be the one called unless specified explicitly to be different.

Imagine this was not the case; it would be impossible to create wrapper contracts like this since a base contract would have no context that it is being wrapped, and thus would have no idea that it would need to call the "wrapped" version of a function rather than its own.

Thus we always call the "most derived" version of a function. Since we know the outer most contract always has context of the contracts it wraps, this pattern allows for exactly these scenarios where we are looking to extend the functionality of some base contract to do something more.

  • 1
    Thanks your explanation is better than the docs. Docs' A call to Final.kill() will call Base2.kill as the most derived override doesn't make sense to me because both base1,2 inherits the same class. So not sure why Final.kill() will call Base2.kill first rather than calling Base1.kill – bbusdriver May 22 at 18:24
  • Anyways, based on your answer I understood this concept in the following way: 1. all contracts (including inherited ones) are flattened into a single file 2. the top level contract's function (identical func name & params) is always called 3. so in our case, line addTokenTo in _mint from ERC721BasicToken will be directed back to addTokenTo in ERC721Token since their names are identical and sit at the top level. Am I correct? – bbusdriver May 22 at 18:24
  • 1
    Sounds right to me. – Shawn Tabrizi May 22 at 19:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.