mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
docs: Literal suffixes
This commit is contained in:
parent
2bf76afec1
commit
edcc3af9c8
@ -141,7 +141,7 @@ Function Visibility Specifiers
|
|||||||
- ``internal``: only visible internally
|
- ``internal``: only visible internally
|
||||||
|
|
||||||
|
|
||||||
.. index:: modifiers, pure, view, payable, constant, anonymous, indexed
|
.. index:: modifiers, pure, view, payable, constant, anonymous, indexed, literal;suffix
|
||||||
|
|
||||||
Modifiers
|
Modifiers
|
||||||
=========
|
=========
|
||||||
@ -157,4 +157,4 @@ Modifiers
|
|||||||
behaviour to be changed in derived contracts.
|
behaviour to be changed in derived contracts.
|
||||||
- ``override``: States that this function, modifier or public state variable changes
|
- ``override``: States that this function, modifier or public state variable changes
|
||||||
the behaviour of a function or modifier in a base contract.
|
the behaviour of a function or modifier in a base contract.
|
||||||
|
- ``suffix`` for free functions: Designates the function as a :ref:`literal suffix<literal_suffixes>` definition.
|
||||||
|
@ -41,6 +41,10 @@ that call them, similar to internal library functions.
|
|||||||
is that free functions do not have direct access to the variable ``this``, storage variables and functions
|
is that free functions do not have direct access to the variable ``this``, storage variables and functions
|
||||||
not in their scope.
|
not in their scope.
|
||||||
|
|
||||||
|
There is a special category of free functions called :ref:`literal suffixes<literal_suffixes>`.
|
||||||
|
Such functions are marked with the ``suffix`` modifier, and can be used to define convenient
|
||||||
|
conversions from literals to arbitrary types.
|
||||||
|
|
||||||
.. _function-parameters-return-variables:
|
.. _function-parameters-return-variables:
|
||||||
|
|
||||||
Function Parameters and Return Variables
|
Function Parameters and Return Variables
|
||||||
|
@ -195,6 +195,42 @@ can still return a value to the caller by use of the ``return`` statement.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.. index:: ! literal suffix; suffix call syntax
|
||||||
|
|
||||||
|
Suffix Calls
|
||||||
|
------------
|
||||||
|
|
||||||
|
For free functions designated as :ref:`literal suffix<literal_suffixes>` definitions there is
|
||||||
|
another way to perform a function call when the argument is a literal.
|
||||||
|
The functions from the example below can be used as suffixes:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity ^0.8.21;
|
||||||
|
|
||||||
|
type Integer is int;
|
||||||
|
type Float is uint;
|
||||||
|
|
||||||
|
function i(int value) pure suffix returns (Integer) {
|
||||||
|
return Integer.wrap(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function f(uint128 mantissa, uint128 exponent) pure suffix returns (Float) {
|
||||||
|
return Float.wrap((mantissa << 128) | exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
``42 i`` and ``4.2 f`` are valid ways to call the functions defined above, equivalent to ``i(42)``
|
||||||
|
and ``f(42, 1)``, respectively.
|
||||||
|
|
||||||
|
For single-parameter suffixes, this call syntax is equivalent to passing the literal as an argument
|
||||||
|
to an internal function call.
|
||||||
|
For two-parameter suffixes, :ref:`fractional decomposition<fractional_decomposition>` is performed
|
||||||
|
first in order to obtain the two input values.
|
||||||
|
|
||||||
|
See the section on :ref:`calling suffix functions<calling_suffix_functions>` for more information
|
||||||
|
on the limitations of this call syntax.
|
||||||
|
|
||||||
|
|
||||||
.. index:: ! new, contracts;creating
|
.. index:: ! new, contracts;creating
|
||||||
|
|
||||||
|
@ -26,4 +26,6 @@ tuple with a second ``bool`` value denoting success.
|
|||||||
|
|
||||||
.. include:: types/operators.rst
|
.. include:: types/operators.rst
|
||||||
|
|
||||||
|
.. include:: types/literal-suffixes.rst
|
||||||
|
|
||||||
.. include:: types/conversion.rst
|
.. include:: types/conversion.rst
|
||||||
|
269
docs/types/literal-suffixes.rst
Normal file
269
docs/types/literal-suffixes.rst
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
.. index:: ! literal suffix
|
||||||
|
.. _literal_suffixes:
|
||||||
|
|
||||||
|
Literal Suffixes
|
||||||
|
================
|
||||||
|
|
||||||
|
While Solidity :ref:`provides implicit conversions<types-conversion-literals>` from its literals to selected types,
|
||||||
|
there are types for which no built-in conversions are available (most notably the
|
||||||
|
:ref:`user-defined value types<user-defined-value-types>`).
|
||||||
|
|
||||||
|
To fill this gap, it is possible to define custom conversions as *literal suffixes*.
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
:force:
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity ^0.8.21;
|
||||||
|
|
||||||
|
type Coin is uint;
|
||||||
|
using {add as +, eq as ==} for Coin global;
|
||||||
|
|
||||||
|
function add(Coin a, Coin b) pure returns (Coin) {
|
||||||
|
return Coin.wrap(Coin.unwrap(a) + Coin.unwrap(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
function eq(Coin a, Coin b) pure returns (bool) {
|
||||||
|
return Coin.unwrap(a) == Coin.unwrap(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function c(uint mantissa, uint exponent) pure suffix returns (Coin) {
|
||||||
|
return Coin.wrap(mantissa * 10**6 / 10**exponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
function uc(uint microValue) pure suffix returns (Coin) {
|
||||||
|
return Coin.wrap(microValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
contract CoinSeller {
|
||||||
|
mapping(address => Coin) balances;
|
||||||
|
|
||||||
|
function buy() public payable {
|
||||||
|
require(msg.value == 1 ether);
|
||||||
|
assert(1.5 c == 1_500_000 uc);
|
||||||
|
balances[msg.sender] = balances[msg.sender] + 1.5 c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.. index:: function;call
|
||||||
|
.. _calling_suffix_functions:
|
||||||
|
|
||||||
|
Calling Suffix Functions
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
There are two ways to call a suffix function: a *suffix call* and a *function call*.
|
||||||
|
|
||||||
|
.. index:: ! literal suffix; suffix call syntax
|
||||||
|
|
||||||
|
Suffix Call Syntax
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
A suffix call has the same syntax as a literal with a :ref:`denomination<denominations>`:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
42 suffix;
|
||||||
|
1.23 suffix;
|
||||||
|
0x1234 suffix;
|
||||||
|
'abc' suffix;
|
||||||
|
hex"12ff" suffix;
|
||||||
|
unicode"😃" suffix;
|
||||||
|
true suffix;
|
||||||
|
|
||||||
|
The literal passed as input to the suffix function must be immediately followed by the name of the suffix.
|
||||||
|
The two must be separated by whitespace unless it is a string, unicode or hexadecimal string literal,
|
||||||
|
in which case the whitespace is optional (i.e. ``'abc'suffix`` is also allowed).
|
||||||
|
|
||||||
|
This call syntax supports only a single literal argument.
|
||||||
|
Variables or expressions (even as simple as wrapping the literal in parentheses) are not allowed.
|
||||||
|
:ref:`Suffix functions defined with two parameters<suffix_function_parameters>` are also invoked with
|
||||||
|
one literal - the :ref:`decomposition<fractional_decomposition>` of the literal into two values is
|
||||||
|
performed implicitly by the compiler.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
There are no negative number literals in Solidity.
|
||||||
|
A literal with a minus sign is an expression.
|
||||||
|
``-123 suffix`` is equivalent to ``-(123 suffix)``, so ``suffix`` does not receive ``-123`` as input.
|
||||||
|
The argument is instead ``123``, and the negation is applied to the returned value.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
:ref:`String literal concatenation<string_literal_concatenation>` produces a single literal at
|
||||||
|
compilation time and therefore is not treated as an expression.
|
||||||
|
This means that e.g., ``"abc" "def" suffix`` is a valid suffix call.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Fractional decomposition is performed at compilation time.
|
||||||
|
Using the suffix call syntax does not incur any extra gas cost compared to the equivalent
|
||||||
|
function call.
|
||||||
|
|
||||||
|
.. index:: ! literal suffix; function call syntax, overload
|
||||||
|
.. _calling_suffix_functions_with_function_call_syntax:
|
||||||
|
|
||||||
|
Function Call Syntax
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Suffix definitions are in all respects valid free functions, and this includes the ability to call
|
||||||
|
them directly:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
suffix(42);
|
||||||
|
suffix(123, 2);
|
||||||
|
suffix(0x1234);
|
||||||
|
suffix('abc');
|
||||||
|
suffix(hex"12ff");
|
||||||
|
suffix(unicode"😃");
|
||||||
|
suffix(true);
|
||||||
|
|
||||||
|
This also makes it possible to call such functions with arguments which are not literals.
|
||||||
|
|
||||||
|
Note that the fractional decomposition is not performed for this kind of call -
|
||||||
|
:ref:`two-parameter suffix functions<suffix_function_parameters>` must be explicitly called with
|
||||||
|
two arguments.
|
||||||
|
|
||||||
|
Regardless of the call syntax used and in contrast to applying a denomination, the result of the
|
||||||
|
call is itself not considered a literal.
|
||||||
|
As a consequence, it cannot be used as input of another suffix call, and calculations on it are performed
|
||||||
|
within its type rather than in arbitrary precision (as is the case with calculations on rational number
|
||||||
|
literals):
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
123 suffix1 suffix2; // This will not compile.
|
||||||
|
suffix1(123) suffix2; // This will not compile.
|
||||||
|
|
||||||
|
Such calls are possible only with the function call syntax:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
suffix2(123 suffix1); // This is fine.
|
||||||
|
suffix2(suffix1(123)); // This is fine.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
As all free functions, suffix definitions can be :ref:`overloaded<overload-function>`.
|
||||||
|
Overloaded suffixes, however, cannot be invoked using the suffix call syntax.
|
||||||
|
|
||||||
|
.. index:: ! literal suffix;definition, function;free
|
||||||
|
|
||||||
|
Defining Suffix Functions
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Literal suffixes can be defined by applying the built-in ``suffix`` modifier to a :ref:`free function<functions>`.
|
||||||
|
|
||||||
|
Only pure functions can be used as suffixes.
|
||||||
|
This means that suffixes cannot read or modify blockchain state.
|
||||||
|
As with all pure functions, however, they can perform pure external calls.
|
||||||
|
|
||||||
|
.. index:: literal;address
|
||||||
|
.. _suffix_function_parameters:
|
||||||
|
|
||||||
|
Suffix Function Parameters
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
A suffix function must accept and return exactly one value.
|
||||||
|
As a special case, suffixes on :ref:`rational literals<rational_literals>` can optionally accept two arguments,
|
||||||
|
produced by the :ref:`fractional decomposition<fractional_decomposition>` of such a literal.
|
||||||
|
|
||||||
|
Suffixes can only have parameters of types for which an implicit conversion from a literal exists.
|
||||||
|
For single-parameter suffixes, this includes the following types:
|
||||||
|
|
||||||
|
+-------------------------------------------------------------+----------------------------------------------------------------+
|
||||||
|
| Parameter type | Accepted literals |
|
||||||
|
+=============================================================+================================================================+
|
||||||
|
| ``bool`` | - :ref:`Boolean<booleans>` literals |
|
||||||
|
+-------------------------------------------------------------+----------------------------------------------------------------+
|
||||||
|
| ``uint8``, ..., ``uint256``, ``int8``, ..., ``int256`` | - :ref:`Rational literals<rational_literals>` (including zero) |
|
||||||
|
| | - Hexadecimal number literals |
|
||||||
|
+-------------------------------------------------------------+----------------------------------------------------------------+
|
||||||
|
| ``address`` | - :ref:`Address literals<address_literals>` |
|
||||||
|
+-------------------------------------------------------------+----------------------------------------------------------------+
|
||||||
|
| ``bytes1``, ..., ``bytes32`` | - Hexadecimal number literals (not for ``bytes20``) |
|
||||||
|
| | - :ref:`Hexadecimal string literals<hexadecimal_literals>` |
|
||||||
|
| | - :ref:`String literals<string_literals>` |
|
||||||
|
| | - :ref:`Unicode literals<unicode_literals>` |
|
||||||
|
| | - :ref:`Zero<rational_literals>` |
|
||||||
|
+-------------------------------------------------------------+----------------------------------------------------------------+
|
||||||
|
| ``bytes`` | - :ref:`Hexadecimal string literals<hexadecimal_literals>` |
|
||||||
|
| | - :ref:`String literals<string_literals>` |
|
||||||
|
| | - :ref:`Unicode literals<unicode_literals>` |
|
||||||
|
+-------------------------------------------------------------+----------------------------------------------------------------+
|
||||||
|
| ``string`` | - :ref:`String literals<string_literals>` |
|
||||||
|
| | - :ref:`Unicode literals<unicode_literals>` |
|
||||||
|
+-------------------------------------------------------------+----------------------------------------------------------------+
|
||||||
|
|
||||||
|
For two-parameter suffix functions, the first parameter (representing the mantissa) can be of any integer type.
|
||||||
|
The second parameter (the exponent) must be of an unsigned integer type.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
:ref:`The function call syntax<calling_suffix_functions_with_function_call_syntax>` is the only
|
||||||
|
way to pass a negative integer value into a suffix function.
|
||||||
|
Despite this, signed integer types are allowed for suffix parameters.
|
||||||
|
They are still useful in cases where it is desirable to limit the range of the parameter or to
|
||||||
|
avoid explicit conversions when the return type is signed.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
40-digit literals prefixed with ``0x`` such as, for example, ``0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF``
|
||||||
|
always represent ``address`` literals in the language.
|
||||||
|
To invoke a suffix accepting ``bytes20`` you must use one of the other literal kinds implicitly
|
||||||
|
convertible to ``bytes20``, e.g., a hexadecimal string literal
|
||||||
|
(``hex"dCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF"``).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Suffix functions accepting ``address payable`` are not allowed since address literals are never payable.
|
||||||
|
|
||||||
|
Suffix functions may not accept or return reference types with ``storage`` or ``calldata`` locations.
|
||||||
|
|
||||||
|
.. index:: ! fractional decomposition
|
||||||
|
.. _fractional_decomposition:
|
||||||
|
|
||||||
|
Fractional Decomposition
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
To allow defining suffixes that work with fractional literals, like ``1.23``, the language allows
|
||||||
|
a special form of a suffix definition.
|
||||||
|
Such a suffix can be considered a more general form of a suffix taking a single integer argument.
|
||||||
|
|
||||||
|
A single-parameter suffix can be applied only to those rational number literals which represent
|
||||||
|
integers.
|
||||||
|
Let us consider the following suffix definition:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
function kg(uint grams) pure suffix returns (uint) {
|
||||||
|
return 1000 * grams;
|
||||||
|
}
|
||||||
|
|
||||||
|
The ``kg`` suffix can receive integer values like ``123 kg``, ``1.23e2 kg``, or ``12300e-2 kg``.
|
||||||
|
However, invoking such a suffix with a fractional number (e.g., ``1.23 kg``) triggers an error.
|
||||||
|
We can fix that by adding an *exponent* parameter:
|
||||||
|
|
||||||
|
.. code-block:: solidity
|
||||||
|
|
||||||
|
function kg(uint mantissa, uint exponent) pure suffix returns (uint) {
|
||||||
|
return 1000 * mantissa / 10**exponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
When defined this way, the suffix can handle all the literals it could previously, while ``1.23 kg``
|
||||||
|
also becomes a valid expression, equivalent to ``kg(123, 2)``.
|
||||||
|
|
||||||
|
More generally, the argument of such a suffix call is decomposed into two integer values (``mantissa``
|
||||||
|
and ``exponent``), such that:
|
||||||
|
|
||||||
|
#. ``mantissa * 10**-exponent`` is equal to the value of the literal.
|
||||||
|
#. ``exponent`` is the smallest possible non-negative integer value satisfying the equation.
|
||||||
|
|
||||||
|
The two rules provide unambiguous decomposition in all cases.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
- ``123000`` is decomposed into ``123000 * 10**-0`` (i.e. ``123000`` for ``mantissa`` and ``0`` for ``exponent``).
|
||||||
|
Not ``123 * 10**3`` or ``123000000 * 10**-3``.
|
||||||
|
|
||||||
|
In general, when the suffix is invoked on an integer, ``mantissa`` is always equal to that integer
|
||||||
|
and ``exponent`` is ``0``.
|
||||||
|
- ``1.23`` is decomposed into ``123 * 10**-2``, not ``1.23 * 10**-0`` or ``123000 * 10**-5``.
|
||||||
|
|
||||||
|
In general, when the suffix is invoked on a fractional number, ``exponent`` is the exponent of the
|
||||||
|
lowest positive power of ``10`` that multiplied by the literal produces an integer value.
|
||||||
|
``mantissa`` is the result of that multiplication.
|
||||||
|
|
||||||
|
``exponent`` is never negative and therefore must have an unsigned integer type.
|
@ -8,6 +8,7 @@ The following are called value types because their variables will always be pass
|
|||||||
are used as function arguments or in assignments.
|
are used as function arguments or in assignments.
|
||||||
|
|
||||||
.. index:: ! bool, ! true, ! false
|
.. index:: ! bool, ! true, ! false
|
||||||
|
.. _booleans:
|
||||||
|
|
||||||
Booleans
|
Booleans
|
||||||
--------
|
--------
|
||||||
@ -523,6 +524,9 @@ regardless of the type of the right (exponent) operand.
|
|||||||
String Literals and Types
|
String Literals and Types
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
.. index:: ! literal;string concatenation
|
||||||
|
.. _string_literal_concatenation:
|
||||||
|
|
||||||
String literals are written with either double or single-quotes (``"foo"`` or ``'bar'``), and they can also be split into multiple consecutive parts (``"foo" "bar"`` is equivalent to ``"foobar"``) which can be helpful when dealing with long strings. They do not imply trailing zeroes as in C; ``"foo"`` represents three bytes, not four. As with integer literals, their type can vary, but they are implicitly convertible to ``bytes1``, ..., ``bytes32``, if they fit, to ``bytes`` and to ``string``.
|
String literals are written with either double or single-quotes (``"foo"`` or ``'bar'``), and they can also be split into multiple consecutive parts (``"foo" "bar"`` is equivalent to ``"foobar"``) which can be helpful when dealing with long strings. They do not imply trailing zeroes as in C; ``"foo"`` represents three bytes, not four. As with integer literals, their type can vary, but they are implicitly convertible to ``bytes1``, ..., ``bytes32``, if they fit, to ``bytes`` and to ``string``.
|
||||||
|
|
||||||
For example, with ``bytes32 samevar = "stringliteral"`` the string literal is interpreted in its raw byte form when assigned to a ``bytes32`` type.
|
For example, with ``bytes32 samevar = "stringliteral"`` the string literal is interpreted in its raw byte form when assigned to a ``bytes32`` type.
|
||||||
@ -565,6 +569,7 @@ Any Unicode line terminator which is not a newline (i.e. LF, VF, FF, CR, NEL, LS
|
|||||||
terminate the string literal. Newline only terminates the string literal if it is not preceded by a ``\``.
|
terminate the string literal. Newline only terminates the string literal if it is not preceded by a ``\``.
|
||||||
|
|
||||||
.. index:: ! literal;unicode
|
.. index:: ! literal;unicode
|
||||||
|
.. _unicode_literals:
|
||||||
|
|
||||||
Unicode Literals
|
Unicode Literals
|
||||||
----------------
|
----------------
|
||||||
@ -576,7 +581,8 @@ They also support the very same escape sequences as regular string literals.
|
|||||||
|
|
||||||
string memory a = unicode"Hello 😃";
|
string memory a = unicode"Hello 😃";
|
||||||
|
|
||||||
.. index:: ! literal;hexadecimal, bytes
|
.. index:: ! literal;hexadecimal string, bytes
|
||||||
|
.. _hexadecimal_literals:
|
||||||
|
|
||||||
Hexadecimal Literals
|
Hexadecimal Literals
|
||||||
--------------------
|
--------------------
|
||||||
@ -587,6 +593,8 @@ hexadecimal digits which can optionally use a single underscore as separator bet
|
|||||||
byte boundaries. The value of the literal will be the binary representation
|
byte boundaries. The value of the literal will be the binary representation
|
||||||
of the hexadecimal sequence.
|
of the hexadecimal sequence.
|
||||||
|
|
||||||
|
.. index:: ! literal;hexadecimal string concatenation
|
||||||
|
|
||||||
Multiple hexadecimal literals separated by whitespace are concatenated into a single literal:
|
Multiple hexadecimal literals separated by whitespace are concatenated into a single literal:
|
||||||
``hex"00112233" hex"44556677"`` is equivalent to ``hex"0011223344556677"``
|
``hex"00112233" hex"44556677"`` is equivalent to ``hex"0011223344556677"``
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
.. index:: ! denomination
|
.. index:: ! denomination, literal;suffix
|
||||||
|
.. _denominations:
|
||||||
|
|
||||||
**************************************
|
**************************************
|
||||||
Units and Globally Available Variables
|
Units and Globally Available Variables
|
||||||
|
Loading…
Reference in New Issue
Block a user