OOPs Concepts

Polymorphism in Solidity

Beginner Level

Polymorphism is a fundamental concept in object-oriented programming that allows a single interface or function to behave differently depending on the context. In Solidity, polymorphism is primarily achieved through function overriding in inheritance, enabling contracts to reuse code while customizing behavior in derived contracts.

Polymorphism allows developers to write flexible, modular, and maintainable smart contracts by letting a single function or interface work with multiple types of contracts.

1. Types of Polymorphism in Solidity

In Solidity, polymorphism can be understood in two main forms:

  • Compile-time polymorphism (Static Polymorphism):
    • Achieved through function overloading, where multiple functions share the same name but have different parameters.
    • Solidity determines which function to call at compile time based on the parameters.
  • Run-time polymorphism (Dynamic Polymorphism):
    • Achieved through inheritance and virtual/override functions.
    • Solidity determines which function to call at runtime, depending on the actual type of the contract instance.

2. Example: Run-time Polymorphism with Virtual & Override


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

// Base contract
contract Animal {
    function makeSound() public pure virtual returns (string memory) {
        return "Some generic animal sound";
    }
}

// Derived contract 1
contract Dog is Animal {
    function makeSound() public pure override returns (string memory) {
        return "Bark!";
    }
}

// Derived contract 2
contract Cat is Animal {
    function makeSound() public pure override returns (string memory) {
        return "Meow!";
    }
}

Explanation:

  • Animal defines a virtual function makeSound().
  • Dog and Cat override this function with their own implementations.
  • Polymorphic behavior: If you have a reference to Animal, the actual function called depends on the type of the derived contract.

Example Usage


Animal myPet;

function setDog() public {
    myPet = new Dog();
}

function setCat() public {
    myPet = new Cat();
}

function petSound() public view returns (string memory) {
    return myPet.makeSound();  // Dynamically calls the correct function
}

  • If myPet points to Dog, petSound() returns "Bark!".
  • If myPet points to Cat, petSound() returns "Meow!".

This is classic run-time polymorphism, where the same interface (makeSound()) behaves differently depending on the actual contract type.

3. Benefits of Polymorphism in Solidity

  • Code Reusability: Base contracts define general behavior that can be reused in multiple derived contracts.
  • Flexibility: Derived contracts can customize behavior without changing the interface.
  • Maintainability: Changes to the base contract can propagate to derived contracts with minimal duplication.
  • Interoperability: Interfaces and abstract contracts enable polymorphic behavior across multiple contracts, widely used in DeFi and token standards like ERC20 and ERC721.

Summary

  • Polymorphism allows a single function or interface to behave differently depending on the contract.
  • In Solidity, it is implemented mainly via virtual/override functions in inheritance (run-time polymorphism).
  • This concept is crucial for building modular, reusable, and flexible smart contracts.

Continue Learning

Explore more topics in Solidity or browse other tutorials.