|
In fact, in the pursuit of eliminating memory-safety and security bugs, Rust can sometimes makes some privacy bugs more likely. For example, in GC'd/RC'd languages, if we have several UserAccount instances and a bunch of long-running operations on them, any particular long-running operation will just hold a reference to the UserAccount itself and modify it at will without any confusion. In Rust, the borrow checker often doesn't let us hold a reference from a long-running operation in practice, so we work around it by putting all UserAccount instances into a Vec<UserAccount>, and have our long-running operations refer to it via an index. However, we might erase and re-use a spot in that Vec, meaning the index now refers to some other UserAccount. If the operation uses that "dangling index", it can lead to leaking sensitive data to the wrong users, or data loss. When using Rust, one has to use discipline to avoid this bug: use IDs into a hash map, or generational indices, or Rc<RefCell<T>>. Each has its own performance hit, but that hit can be worth it to prevent privacy bugs. In the GC'd/RC'd language, this would still be a bug, but it wouldn't cause any mixups between different users' data. I'm not saying we should always use GC'd or RC'd languages for privacy-sensitive purposes, but one should be aware of the particular shortcomings of their tools and have proper practices and oversight in place to mitigate them. |
Except the confusion of data races and having multiple concurrent writers more generally. Not a hypothetical: I've worked in a large C# code base where other people had decided it was fine to just pass a bunch of references around to different long running processes, and sure enough, they ended up stomping over each other's assumptions in really dangerous ways.
Unless of course you're actually controlling access to the data somehow (mutex / read/write lock), in which case you can just use _exactly the same pattern_ in Rust... so this whole thing seems like a bit of a red herring.
> [...] so we work around it by putting all UserAccount instances into a Vec<UserAccount> [...]
No, "we" don't. That's one particular (bad) pattern you could choose, and I wouldn't even say it's an obvious alternative. If in your hypothetical alternative programming language you would have just kept a reference to the data (via GC or ref counting, as you said) then why not do exactly the same thing? `Arc` is a thing. It works just fine.
This sounds like a case of trying to come up with convoluted solutions to simple problems and thereby doing something unnecessarily bad that nobody made you do.
Rust certainly has its warts... but this isn't one of them. Rust doesn't make you do what you're describing, and you could equally choose to do the same bad design in your preferred GC language.