User Tools

Site Tools


Sidebar

Welcome to DIDO WIKI

dido:public:ra:1.2_views:3_taxonomic:4_data_tax:08_objects:07_opers:07_special

This is an old revision of the document!


2.3.4.8.4.5 Special Methods

Overview

Return to the Top

Some Object-Oriented Programming (OOP) Languages have the ability to o overload built-in methods defined by the language. Some languages such as ALGOL, FORTRAN, R and Scala allow all operators to be overwritten and even new operators to be defined. Others languages such as Ada, C#, C++, PHP, Python, Ruby and Rust all a limited set of operators to be overwritten. C, Go, Java, JavaScript, Visual Basic are examples that do not allow operators to be overwritten. 1)

Method Overloading, , sometimes termed Operator Overloading, or operator ad hoc polymorphism, is a specific case of polymorphism, where different operators have different implementations depending on their arguments. Operator overloading is generally defined by a programming language, a programmer, or both.

Operator Overloading is “syntactic sugar”, and is used because it allows programming using notation nearer to the target domain and allows user-defined types a similar level of syntactic support as types built into a language. It is common, for example, in scientific computing, where it allows computing representations of mathematical objects to be manipulated with the same syntax as on paper.

Operator overloading does not change the expressive power of a language (with functions), as it can be emulated using function calls. For example, consider variables a, b, c, d of some user-defined type, such as matrices:

Example 1:

  matrix a, b, c, d;
  d = a + b * c;

In a language that supports operator overloading, and with the usual assumption that the '*' operator has higher precedence than the '+' operator, this is a concise way of writing:

Example 2:

  matrix a, b, c, d;
  d = Add ( a, Multiply ( b, c ) );

However, the Example 1 syntax reflects common mathematical usage, but it can obfuscate the underlying fact that a, b, c, d are actually matrices which can be a problem during debugging and performance tuning.

DIDO Specifics

Return to the Top

Ethereum's Solidity does not support Operator Overloading directly, but it does support being able to create libraries of reusable functions that support a way to provide operators for specific types.

Unsigned Integer Math Operators

Return to the Top

Probably the most well known example of reusable library is the SafeMath library2). In essence, the purpose of the SafeMath Library is to provide Overflow, Underflow, and Wrap Around protection while using Solidity's Unsigned Integer (uint).

The following classic Object-Oriented (OO) code example is written in Solidity. The Smart Contract does the following:

  • A Counter smart contract is made (Line 4)
  • It defines an Unsigned Integer ( uint256 ) as a State Variable named counter and initializes it to zero. (Line 6)
    Note: In Solidity, all Unsigned Integers are initialized to zero, but it is best to be explicit.
  • The contract defines two methods that manipulate the value of counter:
    • A public function named increment by one (Line 8)
    • A public function named decrement by one (Line 13)
  • Calling the SafeMath function to modify the unit256 state variable counter (Lines 10 and 15)
pragma solidity ^0.7.1;
// SPDX-License-Identifier: MIT

contract Counter 
{  // Use SafeMath code    
   uint256 counter = 0;
   
   function incrment() 
     public 
   { counter = SafeMath.add ( counter, 1 );
   } // End incrment function
   
   function decrement() 
     public
   { counter = SafeMath.add ( counter, 1 );
   } // End decrement function
        
} // End Counter contract

However, this code can have problems at the range edges of the uint256 type causing Overflow, Underflow, and Wrap Around issues. The orignal Counter Smart contract can be modified to check for the overflow or underflow issue every time the counter is manipulated, but in-line checking can create its own issues. For example, it introduces more lines of code and each line of code has a potential for being incorrect. A very classic error occurs when the code is copied and pasted from some place else and all the references to the variable are not changed correctly.

A solution for these problems was introduced using an external library called SafeMath and the Solidity language using statement. By including this using SafeMath for <BaseType> at the beginning of the Smart Contract and replacing the traditional operators +, -, *, /, % with the following SafeMath defined functions: add, sub, mul, div and mod.

The Counter Smart Contract is modified to use SafeMath:

  • A using for uint256 datatype statement is added (Line 5)
  • Adding the SafeMath function calls to the unit256 state variable counter instead of using explicitly calling the SafeMath functions (Lines 10 and 15)
pragma solidity ^0.7.1;
// SPDX-License-Identifier: MIT

contract Counter
{ using SafeMath for uint256;
  uint256 counter = 0;
    
     function incrment()
       public
     { counter = counter.add(1);
     } // End incrment function
    
    function decrement()
      public
    { counter = counter.sub(1);
    } // End incrment function
    
} // End Counter contract

Starting with Solidity 0.8 release, SafeMath is now integrated into the language and the import of the OpenZeppelin SafeMath is no longer needed. the standard mathematical operators (i.e., +, -, *, /, %) now use the SafeMath library. For Example: a + b now automatically invokes revert on Overflow.

In the event that the Wrap Around behavior is a desired part of the design of the contract, the expression can be surrounded with the unchecked block. For example,

  • Using SafeMath (i.e., Solidity 8.0 or later) causes a revert to ocur when SafeMath is used (Line 12)
  • Subtracting 1 from the minimum value of an uint256 (i.e., 0) as initialized in Line 10, causes a Wrap Around returning a value of type(uint256).max
  • Deactivate SafeMath by placing the statement within a unchecked block (i.e., { and }) (Line 12)
pragma solidity ^0.8.1;
// SPDX-License-Identifier: MIT

contract MyContract 
{
  function test() 
    external 
    pure 
    returns(uint256) 
    { uint256 x = 0;
      unchecked { x--; }
      return x;
    } // End test function 
} // End MyContract

User Defined Types (Structs)

Return to the Top

As of Solidity 8.1, it is possible to defines a library. A library is a kind of contract, that has no Ethereum Storage associated with it and in addition, it cannot hold ether. One way to think bout a solidity library is as a Singleton in the Ethereum Virtual Machine (EVM). In other words, it is a piece of code callable from any contract without the need to redeploy it. 3)

Libraries in Solidity contracts are blocks of reusable code containing functions usable by other contracts on the blockchain network. When used correctly, libraries support modular, Object-Oriented Programming (OOP) designs.

The main advantage for using library is code reusability across multiple contracts preventing duplication of code and the reuse of testing snd documentstion of the code. In addition, libraries save on gas by not deploying the code multiple times on the blockchain.

Libraries are a special form of contracts with the following restrictions:

  • Are singletons
  • Not allowed any storage or state variables that change
  • Cannot have fallback functions
  • Have no event logs
  • Do not hold ether
  • Are stateless
  • Cannot use destroy
  • Cannot inherit or be inherited

Libraries allow for the addition of functionality to the basic types (i.e., uint) or complex user defined types (i.e., struct). Libraries are isolated from other blocks of code (i.e., contracts) that have no rely on the storage (i.e., state variables) from the calling contract and supplied to the functions.4)

Libraries support different Data Types:

  • User defined strut
  • User derinde enum
  • User defined immutable variables (i.e., constant)
    Note: Library constants become part of the Bytecode rather than in storage (i.e., not as variables on the blockchain itself)

Example of using a Library

The following code provides examples for:

  • Creates a library called StudentRecord (Line 4)
  • Creates a user defined type (i.e., struct) defining a StudentRecord concept adding the following fields: (Lines 5-9)
    • name (Line 6)
    • studentNumber (Line 7)
    • totalClassPoints (Line 8)
  • Defines a function named addPoints that accepts two parameters (Lines 11-17):
    • An instance of a StudentRecord in storage (Line 12)
    • The earnedPoints to add to the students record (Line 13)
    • The actual calculation of the students totalClassPoints (Line 16)
    • The end of the definition of addPoints function
  • End of the definition of the library (Line 17)
pragma solidity ^0.8.1;
// SPDX-License-Identifier: MIT

library StudentLibrary
{ struct StudentRecord
    { string name;
      uint studentNumber;
      uint totalClassPoints;
    } // End StudentRecord structure
    
  function addPoints
    ( StudentRecord storage _studentRecord,
      uint _earnedPoints
    )
    public
    { _studentRecord.totalClassPoints += _earnedPoints;
    } // End addPoints function
} // End StudentRecord library

contract MyClass
{ // Uses the newly created StudentLibrary
  mapping ( uint => StudentLibrary.StudentRecord ) studentRoster;
  function addQuizResults() external
  { // Add points for each student from latest quiz 
    StudentLibrary.addPoints ( studentRoster[0], 10 );
    StudentLibrary.addPoints ( studentRoster[1],  5 );
    StudentLibrary.addPoints ( studentRoster[2],  8 );
  } // End addQuizResults function
} // End MyClass contract

In the example, the library code is saved iin the same file as contract MyClass. It could be stored in a separte file and then imported iinto the contract MyClass file. If the StudentLibrary file is kept in its own file in the same directory as the contract MyClass file StudentLibrary.sol.

In the folowing exaple, both the import and the using are used:

  • The entirity of the library StudentLibrary is replaced by an import statement (Line 4)
  • The Using statements extends the instances of StudentRecord with the operations iin the StudentLibrary (Line 7)
  • The code is modified to use the cleaner, more easily read StudentLibrary defined function (Lines 11-13)

This form of defining and usinig a library facilitates the reuse of the library by multiple Smart Contracts, helps with the maintenance by only having the code defined once, and helps with creating Object-Oriented (OO) architectures and designs.

pragma solidity ^0.8.1;
// SPDX-License-Identifier: MIT

import StudentLibrary from "./StudentLibrary.sol";

contract MyClass
{ using StudentLibrary for StudentLibrary.StudentRecord;
  mapping ( uint => StudentLibrary.StudentRecord ) studentRoster;
  function addQuizResults() external
  { // Add points for each student from latest quiz 
    studentRoster[0].addPoints ( 10);
    studentRoster[1].addPoints (  5);
    studentRoster[2].addPoints (  8);
  } // End addQuizResults function
} // End MyClass contract
1)
Wikipedia, Operator overloading, Accessed: 4 November 2021, https://en.wikipedia.org/wiki/Operator_overloading
2)
OpenZeppelin.com, SafeMath, Accessed: 27 December 2021, https://docs.openzeppelin.com/contracts/2.x/api/math
3)
Jorge Izquierdo, Aragon Association, Library Driven Development in Solidity, 13 February 2017, Accessed: 28 December 2021, https://aragon.org/blog/library-driven-development-in-solidity-2bebcaf88736
4)
Crypto Market Pool, Blockcahin Engineer Resource, Libraries in Solidity smart contracts, Accessed 28 December 2021, https://cryptomarketpool.com/libraries-in-solidity/
dido/public/ra/1.2_views/3_taxonomic/4_data_tax/08_objects/07_opers/07_special.1640803327.txt.gz · Last modified: 2021/12/29 13:42 by nick
Translations of this page: