Inheritance from Rust’s Perspective
#![allow(unused)] fn main() { // Data pub struct Data { id: usize, name: String, } // Concrete behavior impl Data { fn new(id: usize, name: impl Into<String>) -> Self { Self { id, name: name.into() } } } // Abstract behavior trait Named { fn name(&self) -> &str; } // Instanced behavior impl Named for Data { fn name(&self) -> &str { &self.name } } }
-
From Rust’s perspective, one where Inheritance was never there, introducing inheritance would look like muddying the water between types and traits.
-
A type is a concrete piece of data and its associated behavior.
A trait is abstract behavior that must be implemented by a type.
A class is a combination of data, behavior, and overrides to that behavior.
-
Coming from rust, an inheritable class looks like a type that is also a trait.
-
This is not an upside, as we can no longer reason about concrete types.
-
Without being able to separate the two, it becomes difficult to reason about generic behavior vs concrete specifics, because in OOP these two concepts are tied up in each other.
-
The convenience of flat field access and DRY in type definitions is not worth the loss in specificity between writing code that delineates between behavior and data.