mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Example is incorrect in the sense that "Free functions" cannot have visibility specified.
		
			
				
	
	
		
			152 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| .. index:: ! using for, library
 | |
| 
 | |
| .. _using-for:
 | |
| 
 | |
| *********
 | |
| Using For
 | |
| *********
 | |
| 
 | |
| The directive ``using A for B;`` can be used to attach
 | |
| functions (``A``) as member functions to any type (``B``).
 | |
| These functions will receive the object they are called on
 | |
| as their first parameter (like the ``self`` variable in Python).
 | |
| 
 | |
| It is valid either at file level or inside a contract,
 | |
| at contract level.
 | |
| 
 | |
| The first part, ``A``, can be one of:
 | |
| 
 | |
| - a list of file-level or library functions (``using {f, g, h, L.t} for uint;``) -
 | |
|   only those functions will be attached to the type.
 | |
| - the name of a library (``using L for uint;``) -
 | |
|   all functions (both public and internal ones) of the library are attached to the type
 | |
| 
 | |
| At file level, the second part, ``B``, has to be an explicit type (without data location specifier).
 | |
| Inside contracts, you can also use ``using L for *;``,
 | |
| which has the effect that all functions of the library ``L``
 | |
| are attached to *all* types.
 | |
| 
 | |
| If you specify a library, *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.
 | |
| 
 | |
| If you use a list of functions (``using {f, g, h, L.t} for uint;``),
 | |
| then the type (``uint``) has to be implicitly convertible to the
 | |
| first parameter of each of these functions. This check is
 | |
| performed even if none of these functions are called.
 | |
| 
 | |
| The ``using A for B;`` directive is active only within the current
 | |
| scope (either the contract or the current module/source unit),
 | |
| including within all of its functions, and has no effect
 | |
| outside of the contract or module in which it is used.
 | |
| 
 | |
| 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,
 | |
| the word ``global`` can be added at the end. This will have the
 | |
| effect that the functions are attached to the type everywhere
 | |
| the type is available (including other files), not only in the
 | |
| scope of the using statement.
 | |
| 
 | |
| Let us rewrite the set example from the
 | |
| :ref:`libraries` section in this way, using file-level functions
 | |
| instead of library functions.
 | |
| 
 | |
| .. code-block:: solidity
 | |
| 
 | |
|     // SPDX-License-Identifier: GPL-3.0
 | |
|     pragma solidity ^0.8.13;
 | |
| 
 | |
|     struct Data { mapping(uint => bool) flags; }
 | |
|     // Now we attach functions to the type.
 | |
|     // The attached functions can be used throughout the rest of the module.
 | |
|     // If you import the module, you have to
 | |
|     // repeat the using directive there, for example as
 | |
|     //   import "flags.sol" as Flags;
 | |
|     //   using {Flags.insert, Flags.remove, Flags.contains}
 | |
|     //     for Flags.Data;
 | |
|     using {insert, remove, contains} for Data;
 | |
| 
 | |
|     function insert(Data storage self, uint value)
 | |
|         returns (bool)
 | |
|     {
 | |
|         if (self.flags[value])
 | |
|             return false; // already there
 | |
|         self.flags[value] = true;
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     function remove(Data storage self, uint value)
 | |
|         returns (bool)
 | |
|     {
 | |
|         if (!self.flags[value])
 | |
|             return false; // not there
 | |
|         self.flags[value] = false;
 | |
|         return true;
 | |
|     }
 | |
| 
 | |
|     function contains(Data storage self, uint value)
 | |
|         view
 | |
|         returns (bool)
 | |
|     {
 | |
|         return self.flags[value];
 | |
|     }
 | |
| 
 | |
| 
 | |
|     contract C {
 | |
|         Data knownValues;
 | |
| 
 | |
|         function register(uint value) public {
 | |
|             // Here, all variables of type 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 built-in types in that way.
 | |
| In this example, we will use a library.
 | |
| 
 | |
| .. code-block:: solidity
 | |
| 
 | |
|     // SPDX-License-Identifier: GPL-3.0
 | |
|     pragma solidity ^0.8.13;
 | |
| 
 | |
|     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 type(uint).max;
 | |
|         }
 | |
|     }
 | |
|     using Search for uint[];
 | |
| 
 | |
|     contract C {
 | |
|         uint[] data;
 | |
| 
 | |
|         function append(uint value) public {
 | |
|             data.push(value);
 | |
|         }
 | |
| 
 | |
|         function replace(uint from, uint to) public {
 | |
|             // This performs the library function call
 | |
|             uint index = data.indexOf(from);
 | |
|             if (index == type(uint).max)
 | |
|                 data.push(to);
 | |
|             else
 | |
|                 data[index] = to;
 | |
|         }
 | |
|     }
 | |
| 
 | |
| Note that all external library calls are actual EVM function calls. This means that
 | |
| 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
 | |
| is when storage reference variables are used or when internal library
 | |
| functions are called.
 |