Solidity has two keywords that are crucial to understand if you want to make use of contract inheritance: virtual
and override
. In this blog post, we'll take a closer look at these keywords and explore how you can use them in Solidity.
A virtual function is a function that a derived contract can override. You can mark a function as virtual by using the virtual
keyword. If a derived contract overrides a virtual function, it must use the override
keyword.
Here's an example of how virtual functions work in Solidity:
pragma solidity ^0.8.0;
contract Droid {
function speak() public virtual returns (string memory) {
return "Common droid tongue";
}
}
contract R2D2 is Droid {
function speak() public virtual override returns (string memory) {
return "Beep boop beep";
}
}
contract C3PO is Droid {
function speak() public virtual override returns (string memory) {
return "Oh my! I do believe they've shot us";
}
}
In this example, we have a base contract called Droid
that defines a virtual function called speak()
. The function returns a string that describes the sound the droid makes. The R2D2
and C3PO
contracts inherit from the Droid
contract and override the speak()
function. The override
keyword indicates that the function is being overridden.
As mentioned above, the override
keyword is used to explicitly indicate that a derived function is intended to override a virtual function in the base contract. It ensures that the derived function has the same function signature as the virtual function it is overriding.
In case you're wondering what a function signature is: it’s a unique identifier that is generated based on the function's name and its input parameter types. It is used to differentiate between different functions with the same name but different input parameter types, allowing Solidity to properly handle function overloading.
In the above code example, the speak()
function is marked as override
in the R2D2
and C3PO
contracts because they override the virtual speak()
function in the base Droid
contract.
Using the virtual
and override
keywords enables you to create more modular and extensible contracts. By defining virtual functions in a base contract, you can create a framework for other developers to build upon. Other devs on your team can then inherit from the base contract and override the virtual functions to create their own customized functionality.
In addition, using inheritance via virtual
and override
makes it easier to maintain contracts. If the base contract needs to be updated, derived contracts will automatically inherit the updated functionality. If a derived contract needs to be updated, it can be done without affecting the base contract or other derived contracts.
In conclusion, the virtual
and override
function keywords are essential tools for using inheritance and, thus, for creating modular and extensible smart contracts. Virtual functions allow derived contracts to customize the functionality of a base contract, while override functions ensure that the derived contract has the same function signature as the virtual function it is overriding. By using inheritance in your codebase, you can create more maintainable and reusable code, which results in fewer headaches for your teammates - and for yourself.
If you enjoyed this post and want to take your Web3 development skills to the next level, I invite you to join Web3 Developer Academy for FREE. Inside the academy, you’ll get free access to our Intro to Web3 Development video course and a developer community of 100+ Web3 enthusiasts from around the globe.