A bird pondering ground travel

How can the Object Oriented paradigm be implemented in Rust?

One of a billion possible  answers    

Implementing Object-Oriented Programming (OOP) concepts in Rust is quite different from traditional OOP languages like Java or C++.
Rust does not have classes but uses structs and enums to create data structures, and implements behaviors through traits and methods.
Rust provides the following functionality:

1. Encapsulation

Encapsulation in Rust is achieved through the use of pub (public) and non-pub (private) access modifiers.
Structs and enums can have fields that are either publicly accessible or private to their module.
Methods can be defined on structs and enums, with the ability to access and modify the internal state of the object.

pub struct Person {
    pub name: String,
    age: u8,
}

impl Person {
    pub fn new(name: String, age: u8) -> Self {
        Person { name, age }
    }

    pub fn say_hello(&self) {
        println!("Hello, my name is {}", self.name);
    }

    // Accessor method for the private field
    pub fn get_age(&self) -> u8 {
        self.age
    }
}

2. Inheritance and Polymorphism

Rust does not support classical inheritance, which is a good thing, but uses traits to define shared behavior.
This allows for polymorphic behavior where different types can be treated through a common interface.
This keeps us from having some the the problems, that will be discussed in a future post, with coupling, cohesion and messaging that can be problematic with some object oriented designs.


pub trait Animal {
    fn make_sound(&self);
}

pub struct Dog;

impl Animal for Dog {
    fn make_sound(&self) {
        println!("Woof!");
    }
}

pub struct Cat;

impl Animal for Cat {
    fn make_sound(&self) {
        println!("Meow!");
    }
}

// Function to demonstrate polymorphism
pub fn make_animal_sound(animal: &dyn Animal) {
    animal.make_sound();
}

3. Composition

Composition over inheritance is a strongly encouraged practice in Rust, allowing objects to be composed of other objects with well-defined interfaces.


pub struct Engine {
    horsepower: u32,
}

pub struct Car {
    engine: Engine,
}

impl Car {
    pub fn new(horsepower: u32) -> Self {
        Car {
            engine: Engine { horsepower }
        }
    }

    pub fn describe(&self) {
        println!("This car has an engine with {} horsepower.", self.engine.horsepower);
    }
}

These examples showcase how Rust allows for OOP principles to be applied in a way that's idiomatic to the language, emphasizing safety, concurrency, and efficiency.