Inheritance in Solidity, Contracts Are Classes
In this tutorial, we’ll learn how you can easily use inheritance to organize your code. In object-oriented programming, a class is a blueprint for creating objects (a particular data structure), providing initial values for state (member variables or attributes), and implementations of behavior (member functions or methods).
In Solidity, a contract acts like a class. You can inherit from a contract to share a common interface (signal other contracts that your contract implement a secific set of functions for eg: ERC20 tokens or NFTs..).
We’ll get back to our Counter smart contract to make a generic counter interface. We’ll define the following contract.
pragma solidity 0.5.17;
contract Counter {
//Event emitted when the value is changed
event ValueChanged(uint256 newValue);
// Private variable of type unsigned int to keep the number of counts
uint256 private count;
constructor(uint256 startValue) public {
count = startValue;
}
// Function that will modify our counter
function setCounter(uint256 newValue) internal {
count = newValue;
emit ValueChanged(count);
}
// Getter to get the count value
function getCount() public view returns (uint256) {
return count;
}
// The function that child contracts need to implement as an increment or decrement
function step() public;
}
Note:
Line 16: The internal keyword for the setCounter function make this function only available to child contract and not be available outside.
Line 27: The step function that need to be implemented by the contracts that will inherit the Counter contract.
Let’s say we want to have a counter that acts as an incrementer and will always add 1 to the counter whenever the step function is called.
contract IncrementCounter is Counter {
constructor(uint256 startValue) Counter(startValue) public {}
function step() public {
setCounter(getCount() + 1);
}
}
You’ll see that:
Line 1: We are using the is keyword to tell the compiler that the IncrementCounter inherits from the Counter contract.
Line 3: If the parent contract has a constructor, we’ll need to call it from the child constructor with the proper parameters
Line 6: We implement the step function where we tell the parent contract what will be the new value. The setCounter call will set the new value and also emit the log event.
Now that we have our IncrementCounter we can also make the same with a CountDown100 for example. This one directly set the starting value at 100 and will decrement the counter when we call the step function.
contract CountDown100 is Counter {
constructor() Counter(100) public {}
function step() public {
setCounter(getCount() - 1);
}
}
In the case where you define a contract with no logic inside (just function or event definition) it’s called an interface. You can for example look at this simplified interface of a ERC20 token:
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
As we saw in this tutorial, it’s easy to use OOP to organize code and make it more understandable in Solidity. In the next lesson, we’ll see how to control access to your smart contract by using modifiers.