mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	User-defined operators: Documentation
This commit is contained in:
		
							parent
							
								
									1a83fa7ebc
								
							
						
					
					
						commit
						2e8d50eca2
					
				| @ -1,6 +1,7 @@ | |||||||
| ### 0.8.19 (unreleased) | ### 0.8.19 (unreleased) | ||||||
| 
 | 
 | ||||||
| Language Features: | Language Features: | ||||||
|  | * Allow defining custom operators for user-defined value types via ``using {f as +} for T global`` syntax. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| Compiler Features: | Compiler Features: | ||||||
| @ -16,6 +17,10 @@ Bugfixes: | |||||||
|  * SMTChecker: Fix internal error caused by unhandled ``z3`` expressions that come from the solver when bitwise operators are used. |  * SMTChecker: Fix internal error caused by unhandled ``z3`` expressions that come from the solver when bitwise operators are used. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | AST Changes: | ||||||
|  |  * AST: Add ``function`` field to ``UnaryOperation`` and ``BinaryOperation`` AST nodes. ``functionList`` in ``UsingForDirective`` AST nodes will now contain ``operator`` and ``definition`` members instead of ``function`` when the list entry defines an operator. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| ### 0.8.18 (2023-02-01) | ### 0.8.18 (2023-02-01) | ||||||
| 
 | 
 | ||||||
| Language Features: | Language Features: | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| .. index:: ! using for, library | .. index:: ! using for, library, ! operator; user-defined | ||||||
| 
 | 
 | ||||||
| .. _using-for: | .. _using-for: | ||||||
| 
 | 
 | ||||||
| @ -6,37 +6,87 @@ | |||||||
| Using For | Using For | ||||||
| ********* | ********* | ||||||
| 
 | 
 | ||||||
| The directive ``using A for B;`` can be used to attach | The directive ``using A for B`` can be used to attach | ||||||
| functions (``A``) as member functions to any type (``B``). | functions (``A``) as operators to user-defined value types | ||||||
| These functions will receive the object they are called on | or as member functions to any type (``B``). | ||||||
|  | The member functions receive the object they are called on | ||||||
| as their first parameter (like the ``self`` variable in Python). | as their first parameter (like the ``self`` variable in Python). | ||||||
|  | The operator functions receive operands as parameters. | ||||||
| 
 | 
 | ||||||
| It is valid either at file level or inside a contract, | It is valid either at file level or inside a contract, | ||||||
| at contract level. | at contract level. | ||||||
| 
 | 
 | ||||||
| The first part, ``A``, can be one of: | The first part, ``A``, can be one of: | ||||||
| 
 | 
 | ||||||
| - A list of file-level or library functions (e.g. ``using {f, g, h, L.t} for uint;``) - | - A list of functions, optionally with an operator name assigned (e.g. | ||||||
|   only those functions will be attached to the type as member functions. |   ``using {f, g as +, h, L.t} for uint``). | ||||||
|   Note that private library functions can only be specified when ``using for`` is inside the library. |   If no operator is specified, the function can be either a library function or a free function and | ||||||
| - The name of a library (e.g. ``using L for uint;``) - |   is attached to the type as a member function. | ||||||
|   all non-private functions of the library are attached to the type. |   Otherwise it must be a free function and it becomes the definition of that operator on the type. | ||||||
|  | - The name of a library (e.g. ``using L for uint``) - | ||||||
|  |   all non-private functions of the library are attached to the type | ||||||
|  |   as member functions | ||||||
| 
 | 
 | ||||||
| At file level, the second part, ``B``, has to be an explicit type (without data location specifier). | At file level, the second part, ``B``, has to be an explicit type (without data location specifier). | ||||||
| Inside contracts, you can also use ``*`` in place of the type (e.g. ``using L for *;``), | Inside contracts, you can also use ``*`` in place of the type (e.g. ``using L for *;``), | ||||||
| which has the effect that all functions of the library ``L`` | which has the effect that all functions of the library ``L`` | ||||||
| are attached to *all* types. | are attached to *all* types. | ||||||
| 
 | 
 | ||||||
| If you specify a library, *all* functions in the library get attached, | If you specify a library, *all* non-private functions in the library get attached, | ||||||
| even those where the type of the first parameter does not | even those where the type of the first parameter does not | ||||||
| match the type of the object. The type is checked at the | match the type of the object. The type is checked at the | ||||||
| point the function is called and function overload | point the function is called and function overload | ||||||
| resolution is performed. | resolution is performed. | ||||||
| 
 | 
 | ||||||
| If you use a list of functions (e.g. ``using {f, g, h, L.t} for uint;``), | If you use a list of functions (e.g. ``using {f, g, h, L.t} for uint``), | ||||||
| then the type (``uint``) has to be implicitly convertible to the | then the type (``uint``) has to be implicitly convertible to the | ||||||
| first parameter of each of these functions. This check is | first parameter of each of these functions. This check is | ||||||
| performed even if none of these functions are called. | performed even if none of these functions are called. | ||||||
|  | Note that private library functions can only be specified when ``using for`` is inside a library. | ||||||
|  | 
 | ||||||
|  | If you define an operator (e.g. ``using {f as +} for T``), then the type (``T``) must be a | ||||||
|  | :ref:`user-defined value type <user-defined-value-types>` and the definition must be a ``pure`` function. | ||||||
|  | Operator definitions must be global. | ||||||
|  | The following operators can be defined this way: | ||||||
|  | 
 | ||||||
|  | +------------+----------+---------------------------------------------+ | ||||||
|  | | Category   | Operator | Possible signatures                         | | ||||||
|  | +============+==========+=============================================+ | ||||||
|  | | Bitwise    | ``&``    | ``function (T, T) pure returns (T)``        | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``|``    | ``function (T, T) pure returns (T)``        | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``^``    | ``function (T, T) pure returns (T)``        | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``~``    | ``function (T) pure returns (T)``           | | ||||||
|  | +------------+----------+---------------------------------------------+ | ||||||
|  | | Arithmetic | ``+``    | ``function (T, T) pure returns (T)``        | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``-``    | ``function (T, T) pure returns (T)``        | | ||||||
|  | |            +          +---------------------------------------------+ | ||||||
|  | |            |          | ``function (T) pure returns (T)``           | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``*``    | ``function (T, T) pure returns (T)``        | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``/``    | ``function (T, T) pure returns (T)``        | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``%``    | ``function (T, T) pure returns (T)``        | | ||||||
|  | +------------+----------+---------------------------------------------+ | ||||||
|  | | Comparison | ``==``   | ``function (T, T) pure returns (bool)``     | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``!=``   | ``function (T, T) pure returns (bool)``     | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``<``    | ``function (T, T) pure returns (bool)``     | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``<=``   | ``function (T, T) pure returns (bool)``     | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``>``    | ``function (T, T) pure returns (bool)``     | | ||||||
|  | |            +----------+---------------------------------------------+ | ||||||
|  | |            | ``>=``   | ``function (T, T) pure returns (bool)``     | | ||||||
|  | +------------+----------+---------------------------------------------+ | ||||||
|  | 
 | ||||||
|  | Note that unary and binary ``-`` need separate definitions. | ||||||
|  | The compiler will choose the right definition based on how the operator is invoked. | ||||||
| 
 | 
 | ||||||
| The ``using A for B;`` directive is active only within the current | The ``using A for B;`` directive is active only within the current | ||||||
| scope (either the contract or the current module/source unit), | scope (either the contract or the current module/source unit), | ||||||
| @ -46,7 +96,7 @@ outside of the contract or module in which it is used. | |||||||
| When the directive is used at file level and applied to a | When the directive is used at file level and applied to a | ||||||
| user-defined type which was defined at file level in the same file, | user-defined type which was defined at file level in the same file, | ||||||
| the word ``global`` can be added at the end. This will have the | the word ``global`` can be added at the end. This will have the | ||||||
| effect that the functions are attached to the type everywhere | effect that the functions and operators are attached to the type everywhere | ||||||
| the type is available (including other files), not only in the | the type is available (including other files), not only in the | ||||||
| scope of the using statement. | scope of the using statement. | ||||||
| 
 | 
 | ||||||
| @ -150,3 +200,37 @@ if you pass memory or value types, a copy will be performed, even in case of the | |||||||
| ``self`` variable. The only situation where no copy will be performed | ``self`` variable. The only situation where no copy will be performed | ||||||
| is when storage reference variables are used or when internal library | is when storage reference variables are used or when internal library | ||||||
| functions are called. | functions are called. | ||||||
|  | 
 | ||||||
|  | Another example shows how to define a custom operator for a user-defined type: | ||||||
|  | 
 | ||||||
|  | .. code-block:: solidity | ||||||
|  | 
 | ||||||
|  |     // SPDX-License-Identifier: GPL-3.0 | ||||||
|  |     pragma solidity ^0.8.19; | ||||||
|  | 
 | ||||||
|  |     type UFixed16x2 is uint16; | ||||||
|  | 
 | ||||||
|  |     using { | ||||||
|  |         add as +, | ||||||
|  |         div as / | ||||||
|  |     } for UFixed16x2 global; | ||||||
|  | 
 | ||||||
|  |     uint32 constant SCALE = 100; | ||||||
|  | 
 | ||||||
|  |     function add(UFixed16x2 a, UFixed16x2 b) pure returns (UFixed16x2) { | ||||||
|  |         return UFixed16x2.wrap(UFixed16x2.unwrap(a) + UFixed16x2.unwrap(b)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function div(UFixed16x2 a, UFixed16x2 b) pure returns (UFixed16x2) { | ||||||
|  |         uint32 a32 = UFixed16x2.unwrap(a); | ||||||
|  |         uint32 b32 = UFixed16x2.unwrap(b); | ||||||
|  |         uint32 result32 = a32 * SCALE / b32; | ||||||
|  |         require(result32 <= type(uint16).max, "Divide overflow"); | ||||||
|  |         return UFixed16x2.wrap(uint16(a32 * SCALE / b32)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     contract Math { | ||||||
|  |         function avg(UFixed16x2 a, UFixed16x2 b) public pure returns (UFixed16x2) { | ||||||
|  |             return (a + b) / UFixed16x2.wrap(200); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | |||||||
| @ -647,11 +647,17 @@ private: | |||||||
|  * 1. `using LibraryName for T` attaches all functions from the library `LibraryName` to the type `T`. |  * 1. `using LibraryName for T` attaches all functions from the library `LibraryName` to the type `T`. | ||||||
|  * 2. `using LibraryName for *` attaches to all types. |  * 2. `using LibraryName for *` attaches to all types. | ||||||
|  * 3. `using {f1, f2, ..., fn} for T` attaches the functions `f1`, `f2`, ..., `fn`, respectively to `T`. |  * 3. `using {f1, f2, ..., fn} for T` attaches the functions `f1`, `f2`, ..., `fn`, respectively to `T`. | ||||||
|  |  * 4. `using {f1 as op1, f2 as op2, ..., fn as opn} for T` implements operator `opn` for type `T` with function `fn`. | ||||||
|  * |  * | ||||||
|  * For version 3, T has to be implicitly convertible to the first parameter type of |  * For version 3, T has to be implicitly convertible to the first parameter type of | ||||||
|  * all functions, and this is checked at the point of the using statement. For versions 1 and |  * all functions, and this is checked at the point of the using statement. For versions 1 and | ||||||
|  * 2, this check is only done when a function is called. |  * 2, this check is only done when a function is called. | ||||||
|  * |  * | ||||||
|  |  * For version 4, T has to be user-defined value type and the function must be pure. | ||||||
|  |  * All parameters and return value of all the functions have to be of type T. | ||||||
|  |  * This version can be combined with version 3 - a single directive may attach functions to the | ||||||
|  |  * type and define operators on it at the same time. | ||||||
|  |  * | ||||||
|  * Finally, `using {f1, f2, ..., fn} for T global` is also valid at file level, as long as T is |  * Finally, `using {f1, f2, ..., fn} for T global` is also valid at file level, as long as T is | ||||||
|  * a user-defined type defined in the same file at file level. In this case, the methods are |  * a user-defined type defined in the same file at file level. In this case, the methods are | ||||||
|  * attached to all objects of that type regardless of scope. |  * attached to all objects of that type regardless of scope. | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user