Why no Inheritance in Rust?
#![allow(unused)] fn main() { pub struct Id { pub id: u32 } impl Id { // methods } // 🔨❌, rust does not have inheritance! pub struct Data: Id { // Inherited "id" field pub name: String, } impl Data { // methods, but also includes Id's methods, or maybe overrides to // those methods. } // ✅ pub struct Data { pub id: Id, pub name: String, } impl Data { // All of data's methods that aren't from traits. } impl SomeTrait for Data { // Implementations for traits in separate impl blocks. } }
-
Inheritance comes with a number of downsides.
-
Heterogeneous by default:
Class inheritance implicitly allows types of different classes to be used interchangeably, without being able to specify a concrete type or if a type is identical to another.
For operations like equality, comparison this allows for comparison and equality that throws and error or otherwise panics.
-
Multiple sources of truth for what makes up a data structure and how it behaves:
A type’s fields are obscured by the inheritance hierarchy.
A type’s methods could be overriding a parent type or be overridden by a child type, it’s hard to tell what the behavior of a type is in complex codebases maintained by multiple parties.
-
Dynamic dispatch as default adds overhead from vtable lookups:
For dynamic dispatch to work, there needs to be somewhere to store information on what methods to call and other pieces of runtime-known pieces of information on the type.
This store is the
vtablefor a value. Method calls will require more dereferences than calling a method for a type that is known at compile time.