diff options
-rw-r--r-- | docs/contracts.rst | 120 | ||||
-rw-r--r-- | docs/contracts/using-for.rst | 119 |
2 files changed, 120 insertions, 119 deletions
diff --git a/docs/contracts.rst b/docs/contracts.rst index 2a397f6d..8d6e2fe4 100644 --- a/docs/contracts.rst +++ b/docs/contracts.rst @@ -767,122 +767,4 @@ constant to be pushed onto the stack and the dispatcher code compares the current address against this constant for any non-view and non-pure function. -.. index:: ! using for, library - -.. _using-for: - -********* -Using For -********* - -The directive ``using A for B;`` can be used to attach library -functions (from the library ``A``) to any type (``B``). -These functions will receive the object they are called on -as their first parameter (like the ``self`` variable in Python). - -The effect of ``using A for *;`` is that the functions from -the library ``A`` are attached to *any* type. - -In both situations, *all* functions in the library are attached, -even those where the type of the first parameter does not -match the type of the object. The type is checked at the -point the function is called and function overload -resolution is performed. - -The ``using A for B;`` directive is active only within the current -contract, including within all of its functions, and has no effect -outside of the contract in which it is used. The directive -may only be used inside a contract, not inside any of its functions. - -By including a library, its data types including library functions are -available without having to add further code. - -Let us rewrite the set example from the -:ref:`libraries` in this way:: - - pragma solidity >=0.4.16 <0.6.0; - - // This is the same code as before, just without comments - library Set { - struct Data { mapping(uint => bool) flags; } - - function insert(Data storage self, uint value) - public - returns (bool) - { - if (self.flags[value]) - return false; // already there - self.flags[value] = true; - return true; - } - - function remove(Data storage self, uint value) - public - returns (bool) - { - if (!self.flags[value]) - return false; // not there - self.flags[value] = false; - return true; - } - - function contains(Data storage self, uint value) - public - view - returns (bool) - { - return self.flags[value]; - } - } - - contract C { - using Set for Set.Data; // this is the crucial change - Set.Data knownValues; - - function register(uint value) public { - // Here, all variables of type Set.Data have - // corresponding member functions. - // The following function call is identical to - // `Set.insert(knownValues, value)` - require(knownValues.insert(value)); - } - } - -It is also possible to extend elementary types in that way:: - - pragma solidity >=0.4.16 <0.6.0; - - library Search { - function indexOf(uint[] storage self, uint value) - public - view - returns (uint) - { - for (uint i = 0; i < self.length; i++) - if (self[i] == value) return i; - return uint(-1); - } - } - - contract C { - using Search for uint[]; - uint[] data; - - function append(uint value) public { - data.push(value); - } - - function replace(uint _old, uint _new) public { - // This performs the library function call - uint index = data.indexOf(_old); - if (index == uint(-1)) - data.push(_new); - else - data[index] = _new; - } - } - -Note that all library calls are actual EVM function calls. This means that -if you pass memory or value types, a copy will be performed, even of the -``self`` variable. The only situation where no copy will be performed -is when storage reference variables are used. +.. include:: contracts/using-for.rst
\ No newline at end of file diff --git a/docs/contracts/using-for.rst b/docs/contracts/using-for.rst new file mode 100644 index 00000000..ef456ff4 --- /dev/null +++ b/docs/contracts/using-for.rst @@ -0,0 +1,119 @@ +.. index:: ! using for, library + +.. _using-for: + +********* +Using For +********* + +The directive ``using A for B;`` can be used to attach library +functions (from the library ``A``) to any type (``B``). +These functions will receive the object they are called on +as their first parameter (like the ``self`` variable in Python). + +The effect of ``using A for *;`` is that the functions from +the library ``A`` are attached to *any* type. + +In both situations, *all* functions in the library are attached, +even those where the type of the first parameter does not +match the type of the object. The type is checked at the +point the function is called and function overload +resolution is performed. + +The ``using A for B;`` directive is active only within the current +contract, including within all of its functions, and has no effect +outside of the contract in which it is used. The directive +may only be used inside a contract, not inside any of its functions. + +By including a library, its data types including library functions are +available without having to add further code. + +Let us rewrite the set example from the +:ref:`libraries` in this way:: + + pragma solidity >=0.4.16 <0.6.0; + + // This is the same code as before, just without comments + library Set { + struct Data { mapping(uint => bool) flags; } + + function insert(Data storage self, uint value) + public + returns (bool) + { + if (self.flags[value]) + return false; // already there + self.flags[value] = true; + return true; + } + + function remove(Data storage self, uint value) + public + returns (bool) + { + if (!self.flags[value]) + return false; // not there + self.flags[value] = false; + return true; + } + + function contains(Data storage self, uint value) + public + view + returns (bool) + { + return self.flags[value]; + } + } + + contract C { + using Set for Set.Data; // this is the crucial change + Set.Data knownValues; + + function register(uint value) public { + // Here, all variables of type Set.Data have + // corresponding member functions. + // The following function call is identical to + // `Set.insert(knownValues, value)` + require(knownValues.insert(value)); + } + } + +It is also possible to extend elementary types in that way:: + + pragma solidity >=0.4.16 <0.6.0; + + library Search { + function indexOf(uint[] storage self, uint value) + public + view + returns (uint) + { + for (uint i = 0; i < self.length; i++) + if (self[i] == value) return i; + return uint(-1); + } + } + + contract C { + using Search for uint[]; + uint[] data; + + function append(uint value) public { + data.push(value); + } + + function replace(uint _old, uint _new) public { + // This performs the library function call + uint index = data.indexOf(_old); + if (index == uint(-1)) + data.push(_new); + else + data[index] = _new; + } + } + +Note that all library calls are actual EVM function calls. This means that +if you pass memory or value types, a copy will be performed, even of the +``self`` variable. The only situation where no copy will be performed +is when storage reference variables are used. |