It's obviously, uh, quite an Exercise for the Reader(tm) to figure out the best path to avoid memory unsafety given races in line with other Go priorities (as a starting point, imagine a ton of expensive atomics accessing certain pairs on the heap, downgraded to regular loads/stores if the compiler can prove it's safe). But I was trying to say it seems harder to get there now that certain things are set in stone and regressing perf of anything is going to be bad for some user out there.
You'd probably hit other walls. I'm def. not trying to say it's straightforward!
Shared state:
ArrayList A with intial buffer B and length L
Thread 1:
Grows A and replaces B with buffer C, length with M
Thread 2:
(Earlier loaded B into a register)
Code says write to A[M-1]. JVM checks M-1 against M but uses B as it was already stored in a register. Now you have a buffer overflow.
Except, people on this thread seem to think this is impossible. How does Java prevent this?
Wouldn't there be an obvious trade off there, requiring an extra heap allocation and indirection every time a slice is used in a data structure? I've always thought of Go as lower-level than Java (since it has explicit pointers, more control over memory layout, etc), which I think makes it a more useful language overall even if not the best fit for every application (since if you do want Java, it already exists and is mature).
In other words, I think both Java's and Go's decisions make sense here.