The answer lies in the answer to why Rust added `dyn traits`…
Indeed Rust striked some kind of sweet spot because it got the defaults right.
Syntactic it mimics mostly the OOP approach, but without the conceptional burdens behind it.
Still Rust could not do without dynamic dispatch (which is the—wrong—default in OOP).
In the (admittedly) seldom cases where you need dynamic dispatch & runtime polymorphism you just need them.
You could build this stuff by hand (and people did in the past in languages without this features built-in) but having dedicated language level support for that makes it much more bearable.
Structs + the impl system is static dispatch. This just can't replace dynamic dispatch. If it could nobody would have ever invented v-tables…
Indeed Rust striked some kind of sweet spot because it got the defaults right.
Syntactic it mimics mostly the OOP approach, but without the conceptional burdens behind it.
Still Rust could not do without dynamic dispatch (which is the—wrong—default in OOP).
In the (admittedly) seldom cases where you need dynamic dispatch & runtime polymorphism you just need them.
You could build this stuff by hand (and people did in the past in languages without this features built-in) but having dedicated language level support for that makes it much more bearable.
Structs + the impl system is static dispatch. This just can't replace dynamic dispatch. If it could nobody would have ever invented v-tables…