diff options
author | chriseth <chris@ethereum.org> | 2019-01-14 23:35:53 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-14 23:35:53 +0800 |
commit | 92b39b62558d228a40a7896b8d43e91b1e01ab1d (patch) | |
tree | 85879249f9b8da118ed7973648779f3d2533d270 | |
parent | 2d4951edf73c7b2e8c1d91628f3e7ec22a2ea8da (diff) | |
parent | 18cceba81f1f0bf45561dc924a68309a1b1878b8 (diff) | |
download | dexon-solidity-92b39b62558d228a40a7896b8d43e91b1e01ab1d.tar.gz dexon-solidity-92b39b62558d228a40a7896b8d43e91b1e01ab1d.tar.zst dexon-solidity-92b39b62558d228a40a7896b8d43e91b1e01ab1d.zip |
Merge pull request #5746 from ethereum/docs-split-functions
[DOCS] Split functions docs
-rw-r--r-- | docs/contracts.rst | 400 | ||||
-rw-r--r-- | docs/contracts/functions.rst | 398 |
2 files changed, 399 insertions, 399 deletions
diff --git a/docs/contracts.rst b/docs/contracts.rst index 859cd9e9..646e4cdc 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -19,405 +19,7 @@ inaccessible. .. include:: contracts/function-modifiers.rst .. include:: contracts/constant-state-variables.rst - -.. index:: ! functions - -.. _functions: - -********* -Functions -********* - -.. _function-parameters-return-variables: - -Function Parameters and Return Variables -======================================== - -As in JavaScript, functions may take parameters as input. Unlike in JavaScript -and C, functions may also return an arbitrary number of values as output. - -Function Parameters -------------------- - -Function parameters are declared the same way as variables, and the name of -unused parameters can be omitted. - -For example, if you want your contract to accept one kind of external call -with two integers, you would use something like:: - - pragma solidity >=0.4.16 <0.6.0; - - contract Simple { - uint sum; - function taker(uint _a, uint _b) public { - sum = _a + _b; - } - } - -Function parameters can be used as any other local variable and they can also be assigned to. - -.. note:: - - An :ref:`external function<external-function-calls>` cannot accept a - multi-dimensional array as an input - parameter. This functionality is possible if you enable the new - experimental ``ABIEncoderV2`` feature by adding ``pragma experimental ABIEncoderV2;`` to your source file. - - An :ref:`internal function<external-function-calls>` can accept a - multi-dimensional array without enabling the feature. - -.. index:: return array, return string, array, string, array of strings, dynamic array, variably sized array, return struct, struct - -Return Variables ----------------- - -Function return variables are declared with the same syntax after the -``returns`` keyword. - -For example, suppose you want to return two results: the sum and the product of -two integers passed as function parameters, then you use something like:: - - pragma solidity >=0.4.16 <0.6.0; - - contract Simple { - function arithmetic(uint _a, uint _b) - public - pure - returns (uint o_sum, uint o_product) - { - o_sum = _a + _b; - o_product = _a * _b; - } - } - -The names of return variables can be omitted. -Return variables can be used as any other local variable and they -are initialized with their :ref:`default value <default-value>` and have that value unless explicitly set. - -You can either explicitly assign to return variables and -then leave the function using ``return;``, -or you can provide return values -(either a single or :ref:`multiple ones<multi-return>`) directly with the ``return`` -statement:: - - pragma solidity >=0.4.16 <0.6.0; - - contract Simple { - function arithmetic(uint _a, uint _b) - public - pure - returns (uint o_sum, uint o_product) - { - return (_a + _b, _a * _b); - } - } - -This form is equivalent to first assigning values to the -return variables and then using ``return;`` to leave the function. - -.. note:: - You cannot return some types from non-internal functions, notably - multi-dimensional dynamic arrays and structs. If you enable the - new experimental ``ABIEncoderV2`` feature by adding ``pragma experimental - ABIEncoderV2;`` to your source file then more types are available, but - ``mapping`` types are still limited to inside a single contract and you - cannot transfer them. - -.. _multi-return: - -Returning Multiple Values -------------------------- - -When a function has multiple return types, the statement ``return (v0, v1, ..., vn)`` can be used to return multiple values. -The number of components must be the same as the number of return types. - -.. index:: ! view function, function;view - -.. _view-functions: - -View Functions -============== - -Functions can be declared ``view`` in which case they promise not to modify the state. - -.. note:: - If the compiler's EVM target is Byzantium or newer (default) the opcode - ``STATICCALL`` is used for ``view`` functions which enforces the state - to stay unmodified as part of the EVM execution. For library ``view`` functions - ``DELEGATECALL`` is used, because there is no combined ``DELEGATECALL`` and ``STATICCALL``. - This means library ``view`` functions do not have run-time checks that prevent state - modifications. This should not impact security negatively because library code is - usually known at compile-time and the static checker performs compile-time checks. - -The following statements are considered modifying the state: - -#. Writing to state variables. -#. :ref:`Emitting events <events>`. -#. :ref:`Creating other contracts <creating-contracts>`. -#. Using ``selfdestruct``. -#. Sending Ether via calls. -#. Calling any function not marked ``view`` or ``pure``. -#. Using low-level calls. -#. Using inline assembly that contains certain opcodes. - -:: - - pragma solidity ^0.5.0; - - contract C { - function f(uint a, uint b) public view returns (uint) { - return a * (b + 42) + now; - } - } - -.. note:: - ``constant`` on functions used to be an alias to ``view``, but this was dropped in version 0.5.0. - -.. note:: - Getter methods are automatically marked ``view``. - -.. note:: - Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode - for ``view`` functions. - This enabled state modifications in ``view`` functions through the use of - invalid explicit type conversions. - By using ``STATICCALL`` for ``view`` functions, modifications to the - state are prevented on the level of the EVM. - -.. index:: ! pure function, function;pure - -.. _pure-functions: - -Pure Functions -============== - -Functions can be declared ``pure`` in which case they promise not to read from or modify the state. - -.. note:: - If the compiler's EVM target is Byzantium or newer (default) the opcode ``STATICCALL`` is used, - which does not guarantee that the state is not read, but at least that it is not modified. - -In addition to the list of state modifying statements explained above, the following are considered reading from the state: - -#. Reading from state variables. -#. Accessing ``address(this).balance`` or ``<address>.balance``. -#. Accessing any of the members of ``block``, ``tx``, ``msg`` (with the exception of ``msg.sig`` and ``msg.data``). -#. Calling any function not marked ``pure``. -#. Using inline assembly that contains certain opcodes. - -:: - - pragma solidity ^0.5.0; - - contract C { - function f(uint a, uint b) public pure returns (uint) { - return a * (b + 42); - } - } - -Pure functions are able to use the `revert()` and `require()` functions to revert -potential state changes when an :ref:`error occurs <assert-and-require>`. - -Reverting a state change is not considered a "state modification", as only changes to the -state made previously in code that did not have the ``view`` or ``pure`` restriction -are reverted and that code has the option to catch the ``revert`` and not pass it on. - -This behaviour is also in line with the ``STATICCALL`` opcode. - -.. warning:: - It is not possible to prevent functions from reading the state at the level - of the EVM, it is only possible to prevent them from writing to the state - (i.e. only ``view`` can be enforced at the EVM level, ``pure`` can not). - -.. note:: - Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode - for ``pure`` functions. - This enabled state modifications in ``pure`` functions through the use of - invalid explicit type conversions. - By using ``STATICCALL`` for ``pure`` functions, modifications to the - state are prevented on the level of the EVM. - -.. note:: - Prior to version 0.4.17 the compiler did not enforce that ``pure`` is not reading the state. - It is a compile-time type check, which can be circumvented doing invalid explicit conversions - between contract types, because the compiler can verify that the type of the contract does - not do state-changing operations, but it cannot check that the contract that will be called - at runtime is actually of that type. - -.. index:: ! fallback function, function;fallback - -.. _fallback-function: - -Fallback Function -================= - -A contract can have exactly one unnamed function. This function cannot have -arguments, cannot return anything and has to have ``external`` visibility. -It is executed on a call to the contract if none of the other -functions match the given function identifier (or if no data was supplied at -all). - -Furthermore, this function is executed whenever the contract receives plain -Ether (without data). Additionally, in order to receive Ether, the fallback function -must be marked ``payable``. If no such function exists, the contract cannot receive -Ether through regular transactions. - -In the worst case, the fallback function can only rely on 2300 gas being -available (for example when `send` or `transfer` is used), leaving little -room to perform other operations except basic logging. The following operations -will consume more gas than the 2300 gas stipend: - -- Writing to storage -- Creating a contract -- Calling an external function which consumes a large amount of gas -- Sending Ether - -Like any function, the fallback function can execute complex operations as long as there is enough gas passed on to it. - -.. note:: - Even though the fallback function cannot have arguments, one can still use ``msg.data`` to retrieve - any payload supplied with the call. - -.. warning:: - The fallback function is also executed if the caller meant to call - a function that is not available. If you want to implement the fallback - function only to receive ether, you should add a check - like ``require(msg.data.length == 0)`` to prevent invalid calls. - -.. warning:: - Contracts that receive Ether directly (without a function call, i.e. using ``send`` or ``transfer``) - but do not define a fallback function - throw an exception, sending back the Ether (this was different - before Solidity v0.4.0). So if you want your contract to receive Ether, - you have to implement a payable fallback function. - -.. warning:: - A contract without a payable fallback function can receive Ether as a recipient of a `coinbase transaction` (aka `miner block reward`) - or as a destination of a ``selfdestruct``. - - A contract cannot react to such Ether transfers and thus also cannot reject them. This is a design choice of the EVM and Solidity cannot work around it. - - It also means that ``address(this).balance`` can be higher than the sum of some manual accounting implemented in a contract (i.e. having a counter updated in the fallback function). - -:: - - pragma solidity ^0.5.0; - - contract Test { - // This function is called for all messages sent to - // this contract (there is no other function). - // Sending Ether to this contract will cause an exception, - // because the fallback function does not have the `payable` - // modifier. - function() external { x = 1; } - uint x; - } - - - // This contract keeps all Ether sent to it with no way - // to get it back. - contract Sink { - function() external payable { } - } - - contract Caller { - function callTest(Test test) public returns (bool) { - (bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()")); - require(success); - // results in test.x becoming == 1. - - // address(test) will not allow to call ``send`` directly, since ``test`` has no payable - // fallback function. It has to be converted to the ``address payable`` type via an - // intermediate conversion to ``uint160`` to even allow calling ``send`` on it. - address payable testPayable = address(uint160(address(test))); - - // If someone sends ether to that contract, - // the transfer will fail, i.e. this returns false here. - return testPayable.send(2 ether); - } - } - -.. index:: ! overload - -.. _overload-function: - -Function Overloading -==================== - -A contract can have multiple functions of the same name but with different parameter -types. -This process is called "overloading" and also applies to inherited functions. -The following example shows overloading of the function -``f`` in the scope of contract ``A``. - -:: - - pragma solidity >=0.4.16 <0.6.0; - - contract A { - function f(uint _in) public pure returns (uint out) { - out = _in; - } - - function f(uint _in, bool _really) public pure returns (uint out) { - if (_really) - out = _in; - } - } - -Overloaded functions are also present in the external interface. It is an error if two -externally visible functions differ by their Solidity types but not by their external types. - -:: - - pragma solidity >=0.4.16 <0.6.0; - - // This will not compile - contract A { - function f(B _in) public pure returns (B out) { - out = _in; - } - - function f(address _in) public pure returns (address out) { - out = _in; - } - } - - contract B { - } - - -Both ``f`` function overloads above end up accepting the address type for the ABI although -they are considered different inside Solidity. - -Overload resolution and Argument matching ------------------------------------------ - -Overloaded functions are selected by matching the function declarations in the current scope -to the arguments supplied in the function call. Functions are selected as overload candidates -if all arguments can be implicitly converted to the expected types. If there is not exactly one -candidate, resolution fails. - -.. note:: - Return parameters are not taken into account for overload resolution. - -:: - - pragma solidity >=0.4.16 <0.6.0; - - contract A { - function f(uint8 _in) public pure returns (uint8 out) { - out = _in; - } - - function f(uint256 _in) public pure returns (uint256 out) { - out = _in; - } - } - -Calling ``f(50)`` would create a type error since ``50`` can be implicitly converted both to ``uint8`` -and ``uint256`` types. On another hand ``f(256)`` would resolve to ``f(uint256)`` overload as ``256`` cannot be implicitly -converted to ``uint8``. +.. include:: contracts/functions.rst .. include:: contracts/events.rst diff --git a/docs/contracts/functions.rst b/docs/contracts/functions.rst new file mode 100644 index 00000000..76245952 --- /dev/null +++ b/docs/contracts/functions.rst @@ -0,0 +1,398 @@ +.. index:: ! functions + +.. _functions: + +********* +Functions +********* + +.. _function-parameters-return-variables: + +Function Parameters and Return Variables +======================================== + +As in JavaScript, functions may take parameters as input. Unlike in JavaScript +and C, functions may also return an arbitrary number of values as output. + +Function Parameters +------------------- + +Function parameters are declared the same way as variables, and the name of +unused parameters can be omitted. + +For example, if you want your contract to accept one kind of external call +with two integers, you would use something like:: + + pragma solidity >=0.4.16 <0.6.0; + + contract Simple { + uint sum; + function taker(uint _a, uint _b) public { + sum = _a + _b; + } + } + +Function parameters can be used as any other local variable and they can also be assigned to. + +.. note:: + + An :ref:`external function<external-function-calls>` cannot accept a + multi-dimensional array as an input + parameter. This functionality is possible if you enable the new + experimental ``ABIEncoderV2`` feature by adding ``pragma experimental ABIEncoderV2;`` to your source file. + + An :ref:`internal function<external-function-calls>` can accept a + multi-dimensional array without enabling the feature. + +.. index:: return array, return string, array, string, array of strings, dynamic array, variably sized array, return struct, struct + +Return Variables +---------------- + +Function return variables are declared with the same syntax after the +``returns`` keyword. + +For example, suppose you want to return two results: the sum and the product of +two integers passed as function parameters, then you use something like:: + + pragma solidity >=0.4.16 <0.6.0; + + contract Simple { + function arithmetic(uint _a, uint _b) + public + pure + returns (uint o_sum, uint o_product) + { + o_sum = _a + _b; + o_product = _a * _b; + } + } + +The names of return variables can be omitted. +Return variables can be used as any other local variable and they +are initialized with their :ref:`default value <default-value>` and have that value unless explicitly set. + +You can either explicitly assign to return variables and +then leave the function using ``return;``, +or you can provide return values +(either a single or :ref:`multiple ones<multi-return>`) directly with the ``return`` +statement:: + + pragma solidity >=0.4.16 <0.6.0; + + contract Simple { + function arithmetic(uint _a, uint _b) + public + pure + returns (uint o_sum, uint o_product) + { + return (_a + _b, _a * _b); + } + } + +This form is equivalent to first assigning values to the +return variables and then using ``return;`` to leave the function. + +.. note:: + You cannot return some types from non-internal functions, notably + multi-dimensional dynamic arrays and structs. If you enable the + new experimental ``ABIEncoderV2`` feature by adding ``pragma experimental + ABIEncoderV2;`` to your source file then more types are available, but + ``mapping`` types are still limited to inside a single contract and you + cannot transfer them. + +.. _multi-return: + +Returning Multiple Values +------------------------- + +When a function has multiple return types, the statement ``return (v0, v1, ..., vn)`` can be used to return multiple values. +The number of components must be the same as the number of return types. + +.. index:: ! view function, function;view + +.. _view-functions: + +View Functions +============== + +Functions can be declared ``view`` in which case they promise not to modify the state. + +.. note:: + If the compiler's EVM target is Byzantium or newer (default) the opcode + ``STATICCALL`` is used for ``view`` functions which enforces the state + to stay unmodified as part of the EVM execution. For library ``view`` functions + ``DELEGATECALL`` is used, because there is no combined ``DELEGATECALL`` and ``STATICCALL``. + This means library ``view`` functions do not have run-time checks that prevent state + modifications. This should not impact security negatively because library code is + usually known at compile-time and the static checker performs compile-time checks. + +The following statements are considered modifying the state: + +#. Writing to state variables. +#. :ref:`Emitting events <events>`. +#. :ref:`Creating other contracts <creating-contracts>`. +#. Using ``selfdestruct``. +#. Sending Ether via calls. +#. Calling any function not marked ``view`` or ``pure``. +#. Using low-level calls. +#. Using inline assembly that contains certain opcodes. + +:: + + pragma solidity ^0.5.0; + + contract C { + function f(uint a, uint b) public view returns (uint) { + return a * (b + 42) + now; + } + } + +.. note:: + ``constant`` on functions used to be an alias to ``view``, but this was dropped in version 0.5.0. + +.. note:: + Getter methods are automatically marked ``view``. + +.. note:: + Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode + for ``view`` functions. + This enabled state modifications in ``view`` functions through the use of + invalid explicit type conversions. + By using ``STATICCALL`` for ``view`` functions, modifications to the + state are prevented on the level of the EVM. + +.. index:: ! pure function, function;pure + +.. _pure-functions: + +Pure Functions +============== + +Functions can be declared ``pure`` in which case they promise not to read from or modify the state. + +.. note:: + If the compiler's EVM target is Byzantium or newer (default) the opcode ``STATICCALL`` is used, + which does not guarantee that the state is not read, but at least that it is not modified. + +In addition to the list of state modifying statements explained above, the following are considered reading from the state: + +#. Reading from state variables. +#. Accessing ``address(this).balance`` or ``<address>.balance``. +#. Accessing any of the members of ``block``, ``tx``, ``msg`` (with the exception of ``msg.sig`` and ``msg.data``). +#. Calling any function not marked ``pure``. +#. Using inline assembly that contains certain opcodes. + +:: + + pragma solidity ^0.5.0; + + contract C { + function f(uint a, uint b) public pure returns (uint) { + return a * (b + 42); + } + } + +Pure functions are able to use the `revert()` and `require()` functions to revert +potential state changes when an :ref:`error occurs <assert-and-require>`. + +Reverting a state change is not considered a "state modification", as only changes to the +state made previously in code that did not have the ``view`` or ``pure`` restriction +are reverted and that code has the option to catch the ``revert`` and not pass it on. + +This behaviour is also in line with the ``STATICCALL`` opcode. + +.. warning:: + It is not possible to prevent functions from reading the state at the level + of the EVM, it is only possible to prevent them from writing to the state + (i.e. only ``view`` can be enforced at the EVM level, ``pure`` can not). + +.. note:: + Prior to version 0.5.0, the compiler did not use the ``STATICCALL`` opcode + for ``pure`` functions. + This enabled state modifications in ``pure`` functions through the use of + invalid explicit type conversions. + By using ``STATICCALL`` for ``pure`` functions, modifications to the + state are prevented on the level of the EVM. + +.. note:: + Prior to version 0.4.17 the compiler did not enforce that ``pure`` is not reading the state. + It is a compile-time type check, which can be circumvented doing invalid explicit conversions + between contract types, because the compiler can verify that the type of the contract does + not do state-changing operations, but it cannot check that the contract that will be called + at runtime is actually of that type. + +.. index:: ! fallback function, function;fallback + +.. _fallback-function: + +Fallback Function +================= + +A contract can have exactly one unnamed function. This function cannot have +arguments, cannot return anything and has to have ``external`` visibility. +It is executed on a call to the contract if none of the other +functions match the given function identifier (or if no data was supplied at +all). + +Furthermore, this function is executed whenever the contract receives plain +Ether (without data). Additionally, in order to receive Ether, the fallback function +must be marked ``payable``. If no such function exists, the contract cannot receive +Ether through regular transactions. + +In the worst case, the fallback function can only rely on 2300 gas being +available (for example when `send` or `transfer` is used), leaving little +room to perform other operations except basic logging. The following operations +will consume more gas than the 2300 gas stipend: + +- Writing to storage +- Creating a contract +- Calling an external function which consumes a large amount of gas +- Sending Ether + +Like any function, the fallback function can execute complex operations as long as there is enough gas passed on to it. + +.. note:: + Even though the fallback function cannot have arguments, one can still use ``msg.data`` to retrieve + any payload supplied with the call. + +.. warning:: + The fallback function is also executed if the caller meant to call + a function that is not available. If you want to implement the fallback + function only to receive ether, you should add a check + like ``require(msg.data.length == 0)`` to prevent invalid calls. + +.. warning:: + Contracts that receive Ether directly (without a function call, i.e. using ``send`` or ``transfer``) + but do not define a fallback function + throw an exception, sending back the Ether (this was different + before Solidity v0.4.0). So if you want your contract to receive Ether, + you have to implement a payable fallback function. + +.. warning:: + A contract without a payable fallback function can receive Ether as a recipient of a `coinbase transaction` (aka `miner block reward`) + or as a destination of a ``selfdestruct``. + + A contract cannot react to such Ether transfers and thus also cannot reject them. This is a design choice of the EVM and Solidity cannot work around it. + + It also means that ``address(this).balance`` can be higher than the sum of some manual accounting implemented in a contract (i.e. having a counter updated in the fallback function). + +:: + + pragma solidity ^0.5.0; + + contract Test { + // This function is called for all messages sent to + // this contract (there is no other function). + // Sending Ether to this contract will cause an exception, + // because the fallback function does not have the `payable` + // modifier. + function() external { x = 1; } + uint x; + } + + + // This contract keeps all Ether sent to it with no way + // to get it back. + contract Sink { + function() external payable { } + } + + contract Caller { + function callTest(Test test) public returns (bool) { + (bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()")); + require(success); + // results in test.x becoming == 1. + + // address(test) will not allow to call ``send`` directly, since ``test`` has no payable + // fallback function. It has to be converted to the ``address payable`` type via an + // intermediate conversion to ``uint160`` to even allow calling ``send`` on it. + address payable testPayable = address(uint160(address(test))); + + // If someone sends ether to that contract, + // the transfer will fail, i.e. this returns false here. + return testPayable.send(2 ether); + } + } + +.. index:: ! overload + +.. _overload-function: + +Function Overloading +==================== + +A contract can have multiple functions of the same name but with different parameter +types. +This process is called "overloading" and also applies to inherited functions. +The following example shows overloading of the function +``f`` in the scope of contract ``A``. + +:: + + pragma solidity >=0.4.16 <0.6.0; + + contract A { + function f(uint _in) public pure returns (uint out) { + out = _in; + } + + function f(uint _in, bool _really) public pure returns (uint out) { + if (_really) + out = _in; + } + } + +Overloaded functions are also present in the external interface. It is an error if two +externally visible functions differ by their Solidity types but not by their external types. + +:: + + pragma solidity >=0.4.16 <0.6.0; + + // This will not compile + contract A { + function f(B _in) public pure returns (B out) { + out = _in; + } + + function f(address _in) public pure returns (address out) { + out = _in; + } + } + + contract B { + } + + +Both ``f`` function overloads above end up accepting the address type for the ABI although +they are considered different inside Solidity. + +Overload resolution and Argument matching +----------------------------------------- + +Overloaded functions are selected by matching the function declarations in the current scope +to the arguments supplied in the function call. Functions are selected as overload candidates +if all arguments can be implicitly converted to the expected types. If there is not exactly one +candidate, resolution fails. + +.. note:: + Return parameters are not taken into account for overload resolution. + +:: + + pragma solidity >=0.4.16 <0.6.0; + + contract A { + function f(uint8 _in) public pure returns (uint8 out) { + out = _in; + } + + function f(uint256 _in) public pure returns (uint256 out) { + out = _in; + } + } + +Calling ``f(50)`` would create a type error since ``50`` can be implicitly converted both to ``uint8`` +and ``uint256`` types. On another hand ``f(256)`` would resolve to ``f(uint256)`` overload as ``256`` cannot be implicitly +converted to ``uint8``. |