While reading Crafting Interpreters, I learned about something called the expression problem. It's a problem I've run into countless times, especially in larger projects, but I never knew it had an actual name. As usual, Eli Bendersky has an in-depth article about the problem and its solution in C++ and Clojure.
After reading Eli's article, I wondered how the problem would manifest in Rust and what the solution would be. Turns out it's not too complicated. Want to add a new type? Just add it and implement all the traits you care about. Want to add a new operation? Define a new trait and implement it on all the types you care about. This article goes into more detail on what that looks like.