-
Notifications
You must be signed in to change notification settings - Fork 99
RFC: static vs dynamic dispatch #297
Description
I'd like to bring up the discussion on traits once again. Most of RTOSes I'm aware of that have any kind of HAL tend to use dynamic dispatch via function pointers to make the abstraction work with one notable exclusion being TinyOS, that uses a specific superset of C — nesC to make compile-time components binding possible.
In reality, it makes very good sense to use static dispatch as chances are that if you're bringing in a wifi hw and mac stack, you will have exactly one hardware for it and there's no need to do dynamic dispatch, you basically hard-code the appropriate hw layer calls in mac layer.
Problem is that static dispatch in rust is not exactly trivial. Here's the snippet from dht demo:
...
single_task {
loop = "run";
args {
timer = &timer;
uart = &uart;
dht = &dht;
}
}
...
#[zinc_task]
fn run(args: &pt::run_args) {
...
DHT is trait-bound over timer and GPIO:
/// Basic DHT22 driver ported over from Arduino example.
pub struct DHT22<'a, T:'a, P:'a> {
gpio: &'a P,
timer: &'a T,
}
Which makes PT args struct bound over them as well and makes run()
function declaration filled with horrible implementation details, the problem that #[zinc_task]
is solving by saving appropriate types in crate context and then modifying actual function arguments.
Problem is that it doesn't scale at all. You can't pass args.dht
down the stack as you have absolutely no way to figure out its type, that is well hidden inside PT guts.
A way to "fix" it is to basically say: screw static dispatch. Makes code simpler to read and use, the only bounding requirements would be lifetimes, the added cost is indirect calls (up to two more instructions on arm?) and .data bloated with vtables.