Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] Clean up inheritance specification. #3729

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 95 additions & 20 deletions docs/contracts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -818,9 +818,9 @@ Additional Resources for Understanding Events
Inheritance
***********

Solidity supports multiple inheritance by copying code including polymorphism.
Solidity supports multiple inheritance including polymorphism.

All function calls are virtual, which means that the most derived function
All function calls (this includes external and internal 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
Expand All @@ -831,11 +831,90 @@ The general inheritance system is very similar to
`Python's <https://docs.python.org/3/tutorial/classes.html#inheritance>`_,
especially concerning multiple inheritance.

Declaring two elements (for example functions) of the same name in
two different contracts that are part of the same inheritance hierarchy,
is called _overriding_. Declaring two elements of the same name in the
same contract is called _overloading_.

If a function is callable on a contract, it must also be callable in the derived contract.
This means that visibility of functions cannot be restricted, but it
can be extended. Mutability in turn, can be restricted, but not extended.

The visibility can change from external to public, but not from public
to external or from external to internal. Functions that are marked ``view`` in the
super contract, can be marked ``pure`` in the derived contract, but not the other
way around:

+---------------------+------------------------------+
| A function | ... can be overridden by a |
| with visibility ... | function with visibility ... |
+=====================+==============================+
| ``external`` | ``external`` or ``public`` |
+---------------------+------------------------------+
| ``public`` | ``public`` |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public is more general than external, please list first to make a logical order.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure? I would find it logical to list it in the external to internal order.

+---------------------+------------------------------+
| ``internal`` | ``internal`` or ``public`` |
Copy link
Contributor

@fulldecent fulldecent Mar 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IGNORE, MY NOTE IS STUPID.

Why not allow a contract with an internal function to be inherited by a contract that broadens that to public or external?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

internal functions can be overridden by a public function (this is stated here) but not by an external function, because an external function cannot be called internally.

public = internal and external
private = internal plus not visible in derived contracts

+---------------------+------------------------------+
| ``private`` | (none) |
+---------------------+------------------------------+

+---------------------+---------------------------------+
| A function | ... can be overridden by a |
| with mutability ... | function with mutability ... |
+=====================+=================================+
| ``payable`` | ``payable`` |
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not yet clear about this rule.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A payable function should be able to be overridden by a function with mutability default, view or pure. You can this already today using boilerplate stubs, see: #3412

Also, this rule is assumed by ERC-721.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that's probably right. @axic what do you think?

+---------------------+---------------------------------+
| (default) | (default), ``view`` or ``pure`` |
+---------------------+---------------------------------+
| ``view`` | ``view`` or ``pure`` |
+---------------------+---------------------------------+
| ``pure`` | ``pure`` |
+---------------------+---------------------------------+

If a function overrides a function from a super contract, it needs the ``override`` specifier,
everything else is treated as an error.

An external function (but not a function of any other visibility) can be overridden by a public
state variable. This means that the public state variable also needs the ``override`` keyword.

Any other use of overriding between functions, modifiers, state variable or user-defined types
(meaning overriding a function with a modifier or a state variable with a function, etc.) is disallowed.
This means that you cannot declare a struct which has the same name as a function in super contract.

Modifiers are treated in much the same way as functions: They use virtual lookup, require the
``override`` specifier, can use overloading and can have a missing implementation.

It is an error for multiple contracts in an inheritance hierarchy to have a member of the same name,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fear this is not formal enough yet.

unless there is a single contract (``C``) which declares the member and all other contracts
that also declare the member inherit from it (directly or indirectly), all declarations
of that member except for the one in ``C`` use the ``override`` keyword, the members
are either all modifiers or all functions and potentially state variables, all inheritance
relations are compatible with
regards to visibility and state mutability as per the above rules and all have exactly the same
parameter and return types or, if there are functions or modifiers of the same name
declared in ``C`` with different parameters, then all of these functions or modifiers
have to be re-stated in all derived contracts that declare at least one of these
functions or modifiers.

This in particular means that `private` members are not hidden from this mechanism and that
overriding and overloading is incompatible. It also means that it is disallowed to inherit
members of the same name that come from different base contracts unless they share a common
base contract that defines the function to be overridden.

The above rule also means that it is illegal to inherit functions of the same name
from two base contracts who do not derive from the same base contract. It is only allowed
if there is a common base contract which also defines a function of this name. In that case,
the most derived contract can even override the function again.

As it is often useful to inherit the natspec comments for functions from super contracts.
This has to be done explicitly using the ``@inherit`` natspec tag. This tag
will inherit all properties that are not re-defined in the function of the derived contract.

Details are given in the following example.

::

pragma solidity ^0.4.16;
pragma solidity ^0.5.0;

contract owned {
function owned() { owner = msg.sender; }
Expand Down Expand Up @@ -1116,13 +1195,13 @@ facilitating patterns like the `Template method <https://en.wikipedia.org/wiki/T
Interfaces
**********

Interfaces are similar to abstract contracts, but they cannot have any functions implemented. There are further restrictions:
Interfaces are restrictions of abstract contracts in the following way:

#. Cannot inherit other contracts or interfaces.
#. Cannot define constructor.
#. Cannot define variables.
#. Cannot define structs.
#. Cannot define enums.
#. Interfaces cannot have implemented functions (only function declarations).
#. Interfaces cannot inherit other contracts (but they can inherit interfaces).
#. Interfaces cannot define a constructor.
#. Interfaces cannot define variables.
#. Functions in interfaces have to have ``external`` visibility.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

must have


Some of these restrictions might be lifted in the future.

Expand All @@ -1136,7 +1215,7 @@ Interfaces are denoted by their own keyword:
pragma solidity ^0.4.11;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please bump this version, because of external.


interface Token {
function transfer(address recipient, uint amount) public;
function transfer(address recipient, uint amount) external;
}

Contracts can inherit interfaces as they would inherit other contracts.
Expand All @@ -1163,17 +1242,13 @@ the state (i.e. if they are ``view`` or ``pure`` functions),
because libraries are assumed to be stateless. In particular, it is
not possible to destroy a library unless Solidity's type system is circumvented.

Libraries can be seen as implicit base contracts of the contracts that use them.
They will not be explicitly visible in the inheritance hierarchy, but calls
to library functions look just like calls to functions of explicit base
contracts (``L.f()`` if ``L`` is the name of the library). Furthermore,
``internal`` functions of libraries are visible in all contracts, just as
if the library were a base contract. Of course, calls to internal functions
use the internal calling convention, which means that all internal types
Library functions can use the ``inline`` keyword. Calling such functions
from another contract will not use ``DELEGATECALL``, but instead,
code of internal library functions and all functions called from therein
will at compile time be pulled into the calling
contract, and a regular ``JUMP`` call will be used.
This means that all internal types
can be passed and memory types will be passed by reference and not copied.
To realize this in the EVM, code of internal library functions
and all functions called from therein will at compile time be pulled into the calling
contract, and a regular ``JUMP`` call will be used instead of a ``DELEGATECALL``.

.. index:: using for, set

Expand Down