Help me understand why Rust APIs are designed this way
I'm learning Rust and recently started exploring libraries like eframe. I understand what the types mean individually (Box, closures, trait objects), but I'm trying to understand the reasoning behind this API design.
For example, here's a minimal eframe application:
use eframe::egui;
struct MyApp;
impl eframe::App for MyApp {
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
ui.label("Hello World!");
}
}
fn main() {
eframe::run_native(
"my app",
eframe::NativeOptions::default(),
Box::new(|_| Ok(Box::new(MyApp))),
)
.unwrap();
}
What I don't understand is why run_native expects a boxed closure that returns a boxed application.
I think I understand why an API might want a Box<dyn App>: every application has a different concrete type, so using a trait object makes sense.
What I'm struggling with is the extra layer of indirection. Why is the application wrapped inside a closure, and why is that closure itself boxed?
I'm not asking "how does this compile?", I understand the syntax. I'm asking about the design rationale. What problem is this API trying to solve? Why is this design preferable to simply passing an instance of MyApp (or using a generic parameter)?
This might sound like I'm overthinking it, but I'm a pretty skeptical learner. I understand concepts much better when I know why a particular design was chosen, not just how it works.
Thanks!