Ok. What's your epic rick sanchez solution to people poorly engineering software? What's better than a bunch of extensible structs that you can associate functions with?
First off, that's not what OOP is. I do that in C++ and I don't consider that to be OOP. I do that in Rust, modulo struct extensibility. Encapsulation is preferable to inheritance. The proper way to reuse code is to generalize it so that instead of dealing with some particular concrete type you introduce a type parameter and constrain it to have whatever properties the code makes use of. That's Haskell's typeclasses and Rust's traits. Trait bounds on a piece of code are self-documenting and checked at compile time. You can substitute any concrete type that implements the required trait(s) without restrictions on its internal composition.
Not that there's any epic solution to software engineering. It is inherently hard. That's part of why OOP caught on, it was a way to systematize software development so that it could scale to more complex problems. The rest is historical accident. What I'm claiming is that a different (though not entirely) set of guiding principles scales much better to a larger class of problems.
The way they talk about safety fills me with foreboding because that kind of stuff translates to "needing to figure out how to fool the language into doing what I want the computer to do."
No, that's not how it works in practice, in my experience. Think of it this way. Rust has rules. One of them is that a mutable reference to something is the only reference to that thing existing at that moment. Another is that a reference to a thing cannot outlive that thing. These are something that C++ doesn't have and that's a major source of crash-causing bugs. Anyways, Rust at compile time ensures these rules are respected through type-checking, borrow-checking etc. It then assumes these rules are respected when transforming the code, optimizing it and ultimately generating machine code. This is all very good, because it frees you as the human from having to worry about these things all the time. If you break the rules the compiler will inform you.
But there is an escape hatch - you can always write
unsafe { }
and inside the rules can be bent, some operations that are otherwise not allowed become available. In unsafe Rust the compiler cannot enforce the rules because it's not smart enough - that becomes your responsibility. As I've said, the compiler does assume afterwards that the rules are respected. You're not allowed to break outside safe Rust code. The idea is that unsafe Rust allows you to implement some things you couldn't do in safe Rust, but you take on responsibility for upholding the rules so that the rest of the code can maintain the benefits of safety.
It's good practice to accompany each unsafe block with a comment that justifies it's use. There are also unsafe functions which are unsafe to call, and whose bodies are implicitly unsafe code. Oh, there's unsafe traits, but these are only unsafe to implement, not to use. Hide the unsafe code behind an interface that ensures safety and you're set.
With the present Rust compiler (after non-lexical lifetimes have been implemented) I feel the only people that complain about fighting the borrow checker on a regular basis are the people that would write terribly buggy C/C++ code.
Look, humans have limited cognitive capacity compared to how complex software can get. You want to offload as much of the necessary but dull and error-prone reasoning as possible to the machine. In my job I have a never-ending stream of problems to solve and I'd rather not spend time shooting myself in the foot.