diff options
-rw-r--r-- | docs/frequently-asked-questions.rst | 17 | ||||
-rw-r--r-- | docs/types.rst | 187 | ||||
-rw-r--r-- | docs/types/conversion.rst | 127 | ||||
-rw-r--r-- | docs/types/mapping-types.rst | 58 |
4 files changed, 187 insertions, 202 deletions
diff --git a/docs/frequently-asked-questions.rst b/docs/frequently-asked-questions.rst index 8d7caefe..20c01e5c 100644 --- a/docs/frequently-asked-questions.rst +++ b/docs/frequently-asked-questions.rst @@ -85,23 +85,6 @@ The key point is that the calling contract needs to know about the function it i See `ping.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/45_ping.sol>`_ and `pong.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/45_pong.sol>`_. -How do you create 2-dimensional arrays? -======================================= - -See `2D_array.sol <https://github.com/fivedogit/solidity-baby-steps/blob/master/contracts/55_2D_array.sol>`_. - -Note that filling a 10x10 square of ``uint8`` + contract creation took more than ``800,000`` -gas at the time of this writing. 17x17 took ``2,000,000`` gas. With the limit at -3.14 million... well, there’s a pretty low ceiling for what you can create right -now. - -Note that merely "creating" the array is free, the costs are in filling it. - -Note2: Optimizing storage access can pull the gas costs down considerably, because -32 ``uint8`` values can be stored in a single slot. The problem is that these optimizations -currently do not work across loops and also have a problem with bounds checking. -You might get much better results in the future, though. - How do I initialize a contract with only a specific amount of wei? ================================================================== diff --git a/docs/types.rst b/docs/types.rst index ea45b7d7..b9c06f6c 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -22,191 +22,8 @@ tuple with a second `bool` value denoting success. .. include:: types/reference-types.rst -.. index:: !mapping -.. _mapping-types: - -Mapping Types -============= - -You declare mapping types with the syntax ``mapping(_KeyType => _ValueType)``. -The ``_KeyType`` can be any elementary type. This means it can be any of -the built-in value types plus ``bytes`` and ``string``. User-defined -or complex types like contract types, enums, mappings, structs and any array type -apart from ``bytes`` and ``string`` are not allowed. -``_ValueType`` can be any type, including mappings. - -You can think of mappings as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_, which are virtually initialised -such that every possible key exists and is mapped to a value whose -byte-representation is all zeros, a type's :ref:`default value <default-value>`. The similarity ends there, the key data is not stored in a -mapping, only its ``keccak256`` hash is used to look up the value. - -Because of this, mappings do not have a length or a concept of a key or -value being set. - -Mappings can only have a data location of ``storage`` and thus -are allowed for state variables, as storage reference types -in functions, or as parameters for library functions. -They cannot be used as parameters or return parameters -of contract functions that are publicly visible. - -You can mark variables of mapping type as ``public`` and Solidity creates a -:ref:`getter <visibility-and-getters>` for you. The ``_KeyType`` becomes a -parameter for the getter. If ``_ValueType`` is a value type or a struct, -the getter returns ``_ValueType``. -If ``_ValueType`` is an array or a mapping, the getter has one parameter for -each ``_KeyType``, recursively. For example with a mapping: - -:: - - pragma solidity >=0.4.0 <0.6.0; - - contract MappingExample { - mapping(address => uint) public balances; - - function update(uint newBalance) public { - balances[msg.sender] = newBalance; - } - } - - contract MappingUser { - function f() public returns (uint) { - MappingExample m = new MappingExample(); - m.update(100); - return m.balances(address(this)); - } - } - - -.. note:: - Mappings are not iterable, but it is possible to implement a data structure - on top of them. For an example, see `iterable mapping <https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol>`_. +.. include:: types/mapping-types.rst .. include:: types/operators.rst -.. index:: ! type;conversion, ! cast - -.. _types-conversion-elementary-types: - -Conversions between Elementary Types -==================================== - -Implicit Conversions --------------------- - -If an operator is applied to different types, the compiler tries to -implicitly convert one of the operands to the type of the other (the same is -true for assignments). In general, an implicit conversion between value-types -is possible if it -makes sense semantically and no information is lost: ``uint8`` is convertible to -``uint16`` and ``int128`` to ``int256``, but ``int8`` is not convertible to ``uint256`` -(because ``uint256`` cannot hold e.g. ``-1``). - -For more details, please consult the sections about the types themselves. - -Explicit Conversions --------------------- - -If the compiler does not allow implicit conversion but you know what you are -doing, an explicit type conversion is sometimes possible. Note that this may -give you some unexpected behaviour and allows you to bypass some security -features of the compiler, so be sure to test that the -result is what you want! Take the following example where you are converting -a negative ``int8`` to a ``uint``: - -:: - - int8 y = -3; - uint x = uint(y); - -At the end of this code snippet, ``x`` will have the value ``0xfffff..fd`` (64 hex -characters), which is -3 in the two's complement representation of 256 bits. - -If an integer is explicitly converted to a smaller type, higher-order bits are -cut off:: - - uint32 a = 0x12345678; - uint16 b = uint16(a); // b will be 0x5678 now - -If an integer is explicitly converted to a larger type, it is padded on the left (i.e. at the higher order end). -The result of the conversion will compare equal to the original integer:: - - uint16 a = 0x1234; - uint32 b = uint32(a); // b will be 0x00001234 now - assert(a == b); - -Fixed-size bytes types behave differently during conversions. They can be thought of as -sequences of individual bytes and converting to a smaller type will cut off the -sequence:: - - bytes2 a = 0x1234; - bytes1 b = bytes1(a); // b will be 0x12 - -If a fixed-size bytes type is explicitly converted to a larger type, it is padded on -the right. Accessing the byte at a fixed index will result in the same value before and -after the conversion (if the index is still in range):: - - bytes2 a = 0x1234; - bytes4 b = bytes4(a); // b will be 0x12340000 - assert(a[0] == b[0]); - assert(a[1] == b[1]); - -Since integers and fixed-size byte arrays behave differently when truncating or -padding, explicit conversions between integers and fixed-size byte arrays are only allowed, -if both have the same size. If you want to convert between integers and fixed-size byte arrays of -different size, you have to use intermediate conversions that make the desired truncation and padding -rules explicit:: - - bytes2 a = 0x1234; - uint32 b = uint16(a); // b will be 0x00001234 - uint32 c = uint32(bytes4(a)); // c will be 0x12340000 - uint8 d = uint8(uint16(a)); // d will be 0x34 - uint8 e = uint8(bytes1(a)); // e will be 0x12 - -.. _types-conversion-literals: - -Conversions between Literals and Elementary Types -================================================= - -Integer Types -------------- - -Decimal and hexadecimal number literals can be implicitly converted to any integer type -that is large enough to represent it without truncation:: - - uint8 a = 12; // fine - uint32 b = 1234; // fine - uint16 c = 0x123456; // fails, since it would have to truncate to 0x3456 - -Fixed-Size Byte Arrays ----------------------- - -Decimal number literals cannot be implicitly converted to fixed-size byte arrays. Hexadecimal -number literals can be, but only if the number of hex digits exactly fits the size of the bytes -type. As an exception both decimal and hexadecimal literals which have a value of zero can be -converted to any fixed-size bytes type:: - - bytes2 a = 54321; // not allowed - bytes2 b = 0x12; // not allowed - bytes2 c = 0x123; // not allowed - bytes2 d = 0x1234; // fine - bytes2 e = 0x0012; // fine - bytes4 f = 0; // fine - bytes4 g = 0x0; // fine - -String literals and hex string literals can be implicitly converted to fixed-size byte arrays, -if their number of characters matches the size of the bytes type:: - - bytes2 a = hex"1234"; // fine - bytes2 b = "xy"; // fine - bytes2 c = hex"12"; // not allowed - bytes2 d = hex"123"; // not allowed - bytes2 e = "x"; // not allowed - bytes2 f = "xyz"; // not allowed - -Addresses ---------- - -As described in :ref:`address_literals`, hex literals of the correct size that pass the checksum -test are of ``address`` type. No other literals can be implicitly converted to the ``address`` type. - -Explicit conversions from ``bytes20`` or any integer type to ``address`` result in ``address payable``. +.. include:: types/conversion.rst
\ No newline at end of file diff --git a/docs/types/conversion.rst b/docs/types/conversion.rst new file mode 100644 index 00000000..5a9f84c0 --- /dev/null +++ b/docs/types/conversion.rst @@ -0,0 +1,127 @@ +.. index:: ! type;conversion, ! cast + +.. _types-conversion-elementary-types: + +Conversions between Elementary Types +==================================== + +Implicit Conversions +-------------------- + +If an operator is applied to different types, the compiler tries to +implicitly convert one of the operands to the type of the other (the same is +true for assignments). In general, an implicit conversion between value-types +is possible if it +makes sense semantically and no information is lost: ``uint8`` is convertible to +``uint16`` and ``int128`` to ``int256``, but ``int8`` is not convertible to ``uint256`` +(because ``uint256`` cannot hold e.g. ``-1``). + +For more details, please consult the sections about the types themselves. + +Explicit Conversions +-------------------- + +If the compiler does not allow implicit conversion but you know what you are +doing, an explicit type conversion is sometimes possible. Note that this may +give you some unexpected behaviour and allows you to bypass some security +features of the compiler, so be sure to test that the +result is what you want! Take the following example where you are converting +a negative ``int8`` to a ``uint``: + +:: + + int8 y = -3; + uint x = uint(y); + +At the end of this code snippet, ``x`` will have the value ``0xfffff..fd`` (64 hex +characters), which is -3 in the two's complement representation of 256 bits. + +If an integer is explicitly converted to a smaller type, higher-order bits are +cut off:: + + uint32 a = 0x12345678; + uint16 b = uint16(a); // b will be 0x5678 now + +If an integer is explicitly converted to a larger type, it is padded on the left (i.e. at the higher order end). +The result of the conversion will compare equal to the original integer:: + + uint16 a = 0x1234; + uint32 b = uint32(a); // b will be 0x00001234 now + assert(a == b); + +Fixed-size bytes types behave differently during conversions. They can be thought of as +sequences of individual bytes and converting to a smaller type will cut off the +sequence:: + + bytes2 a = 0x1234; + bytes1 b = bytes1(a); // b will be 0x12 + +If a fixed-size bytes type is explicitly converted to a larger type, it is padded on +the right. Accessing the byte at a fixed index will result in the same value before and +after the conversion (if the index is still in range):: + + bytes2 a = 0x1234; + bytes4 b = bytes4(a); // b will be 0x12340000 + assert(a[0] == b[0]); + assert(a[1] == b[1]); + +Since integers and fixed-size byte arrays behave differently when truncating or +padding, explicit conversions between integers and fixed-size byte arrays are only allowed, +if both have the same size. If you want to convert between integers and fixed-size byte arrays of +different size, you have to use intermediate conversions that make the desired truncation and padding +rules explicit:: + + bytes2 a = 0x1234; + uint32 b = uint16(a); // b will be 0x00001234 + uint32 c = uint32(bytes4(a)); // c will be 0x12340000 + uint8 d = uint8(uint16(a)); // d will be 0x34 + uint8 e = uint8(bytes1(a)); // e will be 0x12 + +.. _types-conversion-literals: + +Conversions between Literals and Elementary Types +================================================= + +Integer Types +------------- + +Decimal and hexadecimal number literals can be implicitly converted to any integer type +that is large enough to represent it without truncation:: + + uint8 a = 12; // fine + uint32 b = 1234; // fine + uint16 c = 0x123456; // fails, since it would have to truncate to 0x3456 + +Fixed-Size Byte Arrays +---------------------- + +Decimal number literals cannot be implicitly converted to fixed-size byte arrays. Hexadecimal +number literals can be, but only if the number of hex digits exactly fits the size of the bytes +type. As an exception both decimal and hexadecimal literals which have a value of zero can be +converted to any fixed-size bytes type:: + + bytes2 a = 54321; // not allowed + bytes2 b = 0x12; // not allowed + bytes2 c = 0x123; // not allowed + bytes2 d = 0x1234; // fine + bytes2 e = 0x0012; // fine + bytes4 f = 0; // fine + bytes4 g = 0x0; // fine + +String literals and hex string literals can be implicitly converted to fixed-size byte arrays, +if their number of characters matches the size of the bytes type:: + + bytes2 a = hex"1234"; // fine + bytes2 b = "xy"; // fine + bytes2 c = hex"12"; // not allowed + bytes2 d = hex"123"; // not allowed + bytes2 e = "x"; // not allowed + bytes2 f = "xyz"; // not allowed + +Addresses +--------- + +As described in :ref:`address_literals`, hex literals of the correct size that pass the checksum +test are of ``address`` type. No other literals can be implicitly converted to the ``address`` type. + +Explicit conversions from ``bytes20`` or any integer type to ``address`` result in ``address payable``. diff --git a/docs/types/mapping-types.rst b/docs/types/mapping-types.rst new file mode 100644 index 00000000..935ed6b4 --- /dev/null +++ b/docs/types/mapping-types.rst @@ -0,0 +1,58 @@ +.. index:: !mapping +.. _mapping-types: + +Mapping Types +============= + +You declare mapping types with the syntax ``mapping(_KeyType => _ValueType)``. +The ``_KeyType`` can be any elementary type. This means it can be any of +the built-in value types plus ``bytes`` and ``string``. User-defined +or complex types like contract types, enums, mappings, structs and any array type +apart from ``bytes`` and ``string`` are not allowed. +``_ValueType`` can be any type, including mappings. + +You can think of mappings as `hash tables <https://en.wikipedia.org/wiki/Hash_table>`_, which are virtually initialised +such that every possible key exists and is mapped to a value whose +byte-representation is all zeros, a type's :ref:`default value <default-value>`. The similarity ends there, the key data is not stored in a +mapping, only its ``keccak256`` hash is used to look up the value. + +Because of this, mappings do not have a length or a concept of a key or +value being set. + +Mappings can only have a data location of ``storage`` and thus +are allowed for state variables, as storage reference types +in functions, or as parameters for library functions. +They cannot be used as parameters or return parameters +of contract functions that are publicly visible. + +You can mark variables of mapping type as ``public`` and Solidity creates a +:ref:`getter <visibility-and-getters>` for you. The ``_KeyType`` becomes a +parameter for the getter. If ``_ValueType`` is a value type or a struct, +the getter returns ``_ValueType``. +If ``_ValueType`` is an array or a mapping, the getter has one parameter for +each ``_KeyType``, recursively. For example with a mapping: + +:: + + pragma solidity >=0.4.0 <0.6.0; + + contract MappingExample { + mapping(address => uint) public balances; + + function update(uint newBalance) public { + balances[msg.sender] = newBalance; + } + } + + contract MappingUser { + function f() public returns (uint) { + MappingExample m = new MappingExample(); + m.update(100); + return m.balances(address(this)); + } + } + + +.. note:: + Mappings are not iterable, but it is possible to implement a data structure + on top of them. For an example, see `iterable mapping <https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol>`_. |