Composition in Rust and Python
Tags: rust, python, programming, beginners
Published: 2024-05-12 10:09:26

### Disclaimer
_This is more my attempt to explain this topic to myself. How successful it is is for more experienced people to judge. Argumented criticism in an acceptable form is welcome as always_

## Introduction
Composition in programming is a way of building complex structures by combining simple structures. Rust and Python both support composition, which means you can combine the features of different classes or traits to create more complex and powerful classes or types. This approach promotes code reusability and modularity. Let's explore how composition can be used in both languages to model a car rental system.

# Rust Example

In Rust, we can use traits and structs to model different aspects of a car rental system. For example, we might have a `Car` trait, a `Rental` struct, and a `Customer` struct.

```rust
trait Car {
    fn get_make(&self) -> &str;
    fn get_model(&self) -> &str;
}

struct Rental {
    car: Box<dyn Car>,
    customer: String,
    rental_days: u32,
}

struct Customer {
    name: String,
    rentals: Vec<Rental>,
}

struct Sedan {
    make: String,
    model: String,
}

impl Car for Sedan {
    fn get_make(&self) -> &str {
        &self.make
    }

    fn get_model(&self) -> &str {
        &self.model
    }
}

fn main() {
    let sedan = Sedan {
        make: "Citroën".to_string(),
        model: "C3".to_string(),
    };

    let rental = Rental {
        car: Box::new(sedan),
        customer: "John Doe".to_string(),
        rental_days: 7,
    };

    let customer = Customer {
        name: "John Doe".to_string(),
        rentals: vec![rental],
    };

    println!("Customer {} rented a {} {} for {} days.",
             customer.name,
             customer.rentals[1].car.get_make(),
             customer.rentals[1].car.get_model(),
             customer.rentals[1].rental_days);
}
```
Output:
```bash
$ cargo run
Customer Kurmanjan Datka rented a Citroën C3 for 7 days.
```
In this Rust example, we define a `Car` trait that any car type must implement. We then create a `Rental` struct that contains a boxed `Car` trait object, allowing for any type that implements `Car` to be rented. This demonstrates composition by combining different traits and structs to create a more complex system.

# Python Example

In Python, we can achieve a similar effect using classes and inheritance. Python's dynamic typing makes it easy to compose objects from different classes.

```python
from typing import List

# Here we declare classes to use them as types
# later to make our code more readable
class Customer:
    pass

class Rental:
    pass

class Car:
    def __init__(self, make: str, model: str):
        self.make = make
        self.model = model

    def get_make(self) -> str:
        return self.make

    def get_model(self) -> str:
        return self.model


class Rental:
    def __init__(self, car: Car, customer: Customer, rental_days: int):
        self.car = car
        self.customer = customer
        self.rental_days = rental_days


class Customer:
    def __init__(self, name: str):
        self.name = name
        self.rentals: List[Rental] = []

    def add_rental(self, rental: Rental):
        self.rentals.append(rental)


class Sedan(Car):
    pass


sedan = Sedan("Citroën", "C3")
customer = Customer("Rita Levi-Montalcini")
rental = Rental(sedan, customer, 7)
customer.add_rental(rental)

print(
    f"Customer {customer.name} rented a {customer.rentals[0].car.get_make()} {
        customer.rentals[0].car.get_model()} for {customer.rentals[0].rental_days} days."
)
```
Output:
```bash
$ python main.py 
Customer Rita Levi-Montalcini rented a Citroën C3 for 7 days.
```

In the Python example, we define a `Car` class with methods to get the make and model. We then create a `Rental` class that takes a `Car` instance, a customer name, and the number of rental days. The `Customer` class contains a list of rentals. By using inheritance (e.g., `Sedan` inherits from `Car`), we can easily compose different types of cars and rentals.

Both examples demonstrate how composition can be used to build complex systems by combining simpler, reusable components.

## So what are the differences?

The difference in composition between Rust and Python lies in how they organize and utilize objects and data structures, as well as in memory management and type mechanisms. While Python supports inheritance, allowing classes to inherit from other classes, Rust does not support inheritance in the same way. Instead, Rust encourages composition through traits and struct composition. This leads to a more modular and flexible design, where components can be combined in various ways to achieve the desired functionality. Python's inheritance model can lead to more tightly coupled designs, whereas Rust's composition model promotes more decoupled and reusable components. Both options have their pros and cons depending on where you use them.
In summary, while both languages support principles of composition, they do so differently, taking into account their unique features in type typing, memory management, and software architecture.

## These articles may be useful

- [Writing Python like it's Rust](https://kobzol.github.io/rust/python/2023/05/20/writing-python-like-its-rust.html) 
- [Inheritance and Composition: A Python OOP Guide](https://realpython.com/inheritance-composition-python) 
- [Python App: Rental Car Cost Estimator
- ](https://www.youtube.com/watch?v=LcsEf9IdATA) 
- [design-patterns/strategy](https://www.geeksforgeeks.org/inheritance-and-composition-in-python) 
- [Rust takes the composition over inheritance approach](https://medium.com/@rj.geng/rust-takes-the-composition-over-inheritance-approach-c6e116473a7a) 
- [Design patterns strategy](https://refactoring.guru/design-patterns/strategy)

Image created by Bing and edited by me

## Other articles about the similarities and differences between Rust and Python

1. [Python Classes vs. Rust Traits](https://dev.to/antonov_mike/python-classes-vs-rust-traits-a-comparison-of-object-oriented-programming-features-5gbl)
2. [Python classes vs Rust structures](https://dev.to/antonov_mike/python-classes-vs-rust-structures-nod)
3. [Polymorphism in Rust and Python](https://dev.to/antonov_mike/polymorphism-in-rust-and-python-simple-examples-29co)
4. [Abstraction in Rust and Python](https://dev.to/antonov_mike/abstraction-in-rust-and-python-simple-examples-5dd8)
5. [Encapsulation in Rust and Python](https://dev.to/antonov_mike/how-rust-and-python-implement-encapsulation-4ick)
6. [Composition in Rust and Python](https://dev.to/antonov_mike/composition-in-rust-and-python-21c3)