FAQ.01 Why SeaORM does not nest objects for parent-child relation?โ
let cake_with_fruits: Vec<(cake::Model, Vec<fruit::Model>)> =
Cake::find().find_with_related(Fruit).all(db).await?;
Consider the above API, Cake
and Fruit
are two separate models.
If you come from a dynamic language, you'd probably used to:
struct Cake {
id: u64,
fruit: Fruit,
..
}
It's so convenient that you can simply:
let cake = Cake::find().one(db).await?;
println!("Fruit = {}", cake.fruit.name);
Sweet right? Okay so, the problem with this pattern is that it does not fit well with Rust.
Let's look at this playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6fb0a981189ace081fbb2aa04f50146b
struct Parent {
a: u64,
child: Option<Child>,
}
struct ParentWithBox {
a: u64,
child: Option<Box<Child>>,
}
struct Child {
a: u64,
b: u64,
c: u64,
d: u64,
}
fn main() {
dbg!(std::mem::size_of::<Parent>());
dbg!(std::mem::size_of::<ParentWithBox>());
dbg!(std::mem::size_of::<Child>());
}
What's the output you guess?
[src/main.rs:21] std::mem::size_of::<Parent>() = 48
[src/main.rs:22] std::mem::size_of::<ParentWithBox>() = 16
[src/main.rs:23] std::mem::size_of::<Child>() = 32
In dynamic languages, objects are always held by pointers, and that maps to a Box
in Rust. In Rust, we don't put objects in Box
es by default, because it forces the object to be allocated on the heap. And that is an extra cost! Because objects are always first constructed on the stack and then being copied over to the heap.
Ref:
- https://users.rust-lang.org/t/how-to-create-large-objects-directly-in-heap/26405
- https://github.com/PoignardAzur/placement-by-return/blob/placement-by-return/text/0000-placement-by-return.md
We face the dilemma where we either put the object on the stack and waste some space (it takes up 48 bytes no matter child
is None
or not) or put the object in a box and waste some cycles.
If you are new to Rust, all these might be unfamiliar, but a Rust programmer has to consciously make decisions over memory management, and we don't want to make decisions on behalf of our users.
That said, there were proposals to add API with this style to SeaORM, and we might implement that in the future. Hopefully this would shed some light on the matter meanwhile.