x[0] = 10
And instead I have to do: y = x.at[0].set(10)
Of course this has advantages, and I know it sounds lame, but as someone whose brain works in numpy, this is really offputting. x[0] = 10
And instead I have to do: y = x.at[0].set(10)
Of course this has advantages, and I know it sounds lame, but as someone whose brain works in numpy, this is really offputting. arr[1000000] = 1
has to clone the entire array if you want it to be pure, leading to very unpredictable performance. There are also some algorithms that are straight up impossible to (efficiently) implement without mutability. Often, it's exactly those algorithms that are hard to optimize for optimizers like JAX.Specifically in JAX, code that is slow due to copying will often be optimized into mutable code before running for performance reasons. But because JAX still has the gurantees of no mutability, it can do many optimizations such as caching or dead-code elimination.
You are correct about in-depth mutations and resulting complications, but that only strengthens my assertion: immutable should be default, but not compulsory (because sometimes you absolutely need them). And mutability doesn't preclude caching or dead-code elimination; you just have to be more careful. Often it's the case that you can convert a mutable code into an immutable form only for the purpose of analysis, which is definitely harder than an immutable code in the first place but not impossible. Scalar compilers have used SSA---an immutable description for mutable programs---for a long time after all.
for ex, a simple loop in JAX:
def solve(i, v): return i+v
x = jax.lax.fori_loop(0, 5, solve, 10)