Skip to content

Latest commit

 

History

History
91 lines (69 loc) · 2.3 KB

README.md

File metadata and controls

91 lines (69 loc) · 2.3 KB

Object Oriented Programming Features of Rust1

Note: There is no program included in this chapter, as it's notes only.

Characteristics of Object-Oriented Langauges

The Gang of Four defines OOP this way:

Object-oriented programs are made up of objects. An object packages both data and the procedures that operate on that data. The procedures are typically called methods or operations.

Using this definition, Rust is object-oriented: structs and enums have data, and impl blocks provide methods on structs and enums. Even though Rust doesn't call structs or enums objects, they provide the same functionality.

Another aspect associated with OOP is encauspulation; Rust provides pub:

pub struct AveragedCollection {
    list: Vec<i32>,
    average: f64,
}

Yet another aspect is inheritance, gaining the parent object's data and behavior without defining them again. With this definition, Rust is not object-oriented. However, Rust has other tools where you might pick inheritance:

  • Traits support default implementations.
  • Traits support polymorphism, i.e. common behavior.
pub trait Draw {
    fn draw(&self);
}

pub struct Screen {
    pub components: Vec<Box<dyn Draw>>,
}

impl Screen {
    pub fn run(&self) {
        for component in self.components.iter() {
            component.draw();
        }
    }
}

When we use trait objects, Rust must use dynamic dispatch; which incurs a runtime cost over static dispatch and disables inlining. However, we get extra flexibility - so it's a tradeoff worth considering.

Re-imagining the State pattern

A more Rust-y State pattern is using types to encode states and behavior:

pub struct Post {
    content: String,
}

pub struct DraftPost {
    content: String,
}

impl Post {
    pub fn new() -> DraftPost {
        DraftPost {
            content: String::new(),
        }
    }

    pub fn content(&self) -> &str {
        &self.content
    }
}

impl DraftPost {
    pub fn add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }
}

Note that Post::new creates a DraftPost, and only Post has a public content method. It's now impossible to get around these (contract) constraints without a compiler error.

Footnotes

  1. Source: https://doc.rust-lang.org/book/ch17-01-what-is-oo.html