Doesn't the answer depend on whether or not the map is being mutated by other threads concurrently?
To be fair, even in Rust that answer would depend on the specific map implementation - for example if the map internally held a lock to expose a thread-safe non-mut interface, there's a race between when you remove/insert and when you read the size. That suggests that the whole concept of local reasoning about mutable state gets pretty messy pretty quick unless you stick to very basic examples.
> Doesn't the answer depend on whether or not the map is being mutated by other threads concurrently?
Yes. To reason about here, you need to look elsewhere. Reasoning locally about your code doesn't tell you what happens.
> To be fair, even in Rust that answer would depend on the specific map implementation
I'm not convinced that Rust would disappoint here - this example is the essence of what Rust promises to do safely (well, that and GC-less GC). Per tfa:
> for a very, very long time the field has been held back by programming languages with too much mutable aliasing to be tractable.
> And Rust makes this better?
> Yes. Rust references are subject to the "shared-xor-mutable" rule
If you're reading and writing to your map, then no-one else is. It's the reward you get for pushing through the pain of lifetimes/ownership that other languages don't impose on you.
To be fair, I haven't touched Rust since the latest push for async programming... has it really just dropped 'share-xor-mutable' on the floor?
> If you're reading and writing to your map, then no-one else is. It's the reward you get for pushing through the pain of lifetimes/ownership that other languages don't impose on you.
I think you have failed to engage with the thrust of what I said - if the map is Sync in Rust, all bets are thrown out the window of your ability to reason locally about whether this piece of code works just by looking at this function - the map may be mutated between your mutation & read of the size by another thread.
> If you're reading and writing to your map, then no-one else is. It's the reward you get for pushing through the pain of lifetimes/ownership that other languages don't impose on you.
Only if you use mutable references. A lot of Sync code doesn't necessarily give you a mut reference to enforce that exclusion (e.g. lock-free data structures).
> To be fair, I haven't touched Rust since the latest push for async programming... has it really just dropped 'share-xor-mutable' on the floor?
Async has nothing to do with it & share^mut is still correct. I'm trying to highlight that with Sync you can lose that because the interfaces all become share even if they under-the-hood mutate in a thread-safe way.
Ah - the author does call out that Rust can’t do local reasoning perfectly. The other place it comes up aside from the Sync example I describe is RefCell which similarly lets you mutate from behind a shared reference thus also violating local reasoning. The author also describes why Rust deviated here (the niche Rust was moving into with systems programming often needs an escape hatch for some small amount of non-local mutability)
Correct, I'm just highlighting that there are gaps in Rust's ownership model where local reasoning fails. They're fairly narrow compared to other languages, but you do have to know about them.
Pop-quiz: what does this print out?
EDIT: Apologies, I misread your double negative.Nope. I reread it again and I'm still thoroughly confused. Java does have local reasoning, as opposed in particular to JavaScript, which does not?