Disclaimer
The article contains code samples, but not theory and does not pretend to explain the theoretical basis of polymorphism in depth, nor does it explain why and when polymorphism should be used.
The article demonstrates how to implement polymorphism in Rust and Python, but does not explain practical applications of polymorphism in real projects.
Polymorphism
allows you to write code that can work with different types of objects that share some common behavior or interface. For example, you can write a function that can accept any object that can make a sound, such as a dog, a cat, or a bird.
In Rust
one way to achieve polymorphism is to use traits and generics. Traits define a set of methods that a type must implement to satisfy a certain interface. Generics allow you to write code that can work with any type that meets some trait bounds. For example, you can write a function that can accept any type that implements the SoundMaker trait, which defines a method called make_sound. Here is an example of polymorphism in Rust using traits and generics:
// Define a trait that requires a method called make_sound
trait SoundMaker {
fn make_sound(&self);
}
// Implement the trait for different types
impl SoundMaker for String {
fn make_sound(&self) {
println!("{} says hello", self);
}
}
impl SoundMaker for i32 {
fn make_sound(&self) {
println!("{} beeps", self);
}
}
// Write a generic function that can accept any type that implements the trait
fn make_some_sound<T: SoundMaker>(item: T) {
item.make_sound();
}
// Call the function with different types
fn main() {
let name = String::from("Alice");
let number = 42;
make_some_sound(name); // Alice says hello
make_some_sound(number); // 42 beeps
}
In Python
one way to achieve polymorphism is to use duck typing and inheritance. Duck typing is a concept that says that an object's behavior is more important than its type. In other words, if an object can do something, it doesn't matter what type it is. Inheritance is a concept that allows a class to inherit the attributes and methods of another class. For example, you can write a function that can accept any object that has a method called make_sound. Here is an example of polymorphism in Python using duck typing and inheritance:
# A class that has a method called make_sound
class SoundMaker:
def make_sound(self):
pass
# A subclasses that inherit from the base class and override the method
class String(SoundMaker):
def __init__(self, value):
self.value = value
def make_sound(self):
print(f"{self.value} says hello")
class Integer(SoundMaker):
def __init__(self, value):
self.value = value
def make_sound(self):
print(f"{self.value} beeps")
# A function that can accept any object that has a method called make_sound
def make_some_sound(item):
item.make_sound()
# Call the function with different objects
name = String("Alice")
number = Integer(42)
make_some_sound(name) # Alice says hello
make_some_sound(number) # 42 beeps
Conclusion
As you can see, the examples are similar in the sense that they both use a common interface (make_sound) to achieve polymorphism. However, they also differ in the syntax and the concepts they use. Rust is more explicit and type-safe, while Python is more dynamic and flexible. Both languages have their own advantages and disadvantages, depending on the use case and the preference of the programmer.
Top comments (2)
Nice topic and post :D
One note, in order to get all the methods of String/Integer in python you would have to subclass it, in rust by implementing trait you are just extending what can be done with original struct.
Hope this helps!
О! Thank you! I didn't even think of that. Anyway, because of my lack of serious experience in production, every time I think I understand something, I doubt it very much, because all this stuff is very far from how it is applied in real work.