15
A failed experiment with Rust static dispatch - Julio Merino (jmmv.dev)
jmmv.devInitial versions of the EndBASIC Service, and therefore initial versions of EndTRACKER, used dynamic dispatch to support abstract definitions of system services such as the database they talk to and the clock they use. This looked like a bunch of Arc objects passed around and was done to support extremely fast unit testing.
When I generalized the core logic of these services into the III-IV framework, I decided to experiment with a switch to static dispatch. The rationale was that using static dispatch better aligns with the design of well-regarded crates in the Rust ecosystem, and also because I wanted to avoid unnecessary runtime costs in the foundational pieces of my web services.
Let me tell you that this decision was a huge mistake and that the experiment has utterly failed. Using static dispatch has been a constant source of frustration due to the difficulty in passing types around and reasoning about trait bounds. The situation had gotten so bad that I dreaded adding new functionality to my services whenever a change to a statically-typed struct was needed, because that meant adding yet another type parameter and plumbing it through tens of source files.
In lieu of the difficulties, which eventually turned into blockers to implementing new features, I made the choice of going back to dynamic dispatch. The goal was to gain ergonomics at the expense of a supposedly-negligible runtime cost. Let me tell you about the problems I faced, the refactoring journey, and some measurements I gathered after the rewrite.
Unless I’m missing something, I think you can clean it up and keep your static dispatch by turning the Driver struct into a trait:
You’d rename your
struct Driver
tostruct DriverImpl
, define atrait Driver
and for the implementation you’d useimpl Driver for DriverImpl where etc...