I ported Casey Muratori's C++ example of "clean code" to Rust, here what I found
Yesterday I've read an article from Casey Muratori, in which he's trying to make a case against so-called "clean code" practices: inheritance, virtual functions, overrides, SOLID, DRY and etc.
In that article he's using "the example from clean code literature", which boils down to simple Shape class hierarchy: base Shape class with virtual method f32 Area() and a few children -- Circle, Triangle, Square and Rectangle, which override the base method. Then he rewrites it using old-school "struct + enum type" approach, lookup table, and shows how that affects performance.
Finally, after few more iterations, he shows us that we came from 46 cycles / shape to 5.6 cycles / shape (with loop unrolling 3 cycles / shape, which is x15 speedup), using old tricks and not using "clean code approach". So I got curious, is this really that bad? And how's the Rust doing that?
I wrote a dumb and simple equivalent in Rust (I am not an expert, I am still learning). The baseline was using structs and trait with dynamic dispatch. Then I rewrote all the examples (apart from loop unrolling and AVX-whatever stuff), and made a special, rusty thing -- used Rust enums with its full potential. And benched that with criterion crate (sorry, I have no valgrind on windows to check it with iai, but I've written all the necessary benches). Here are the numbers:
| Method | Time | Difference from baseline |
|---|---|---|
| Dynamic dispatch | 632.34 µs | 100% |
| GS with enum field + match | 379.52 µs | 60.01% |
| GS with enum field + match + lookup table | 340.19 µs | 53.79% |
| Rust enums | 366.25 µs | 57.91% |
For me it looks like Rust provides a good way to write an efficient and ergonomic code without all the shenanigans that Casey was trying to do. Maybe it's just a C++ problem? Maybe Casey could use std::variant or other stuff which gives you some sort of type-safety and ergonomics?
Maybe I am a little dummy and made a bad example, or my benchmark is flawed. I hope we can clear that out too. Also I welcome any suggestions and improvements, or different approaches.
But right now I feel like Casey's point doesn't make sense outside of that specific C++ case. Yes, virtual functions and VTables are slow, but modern languages provide good instruments to write clean, reusable and fast code.