What does "immutable" mean and why does it help?
An immutable value cannot be changed after it is created. Operations that appear to modify it return a new value instead, leaving the original intact.
Why this helps, and the reasons compound:
You can reason locally. If a value cannot change, you know what it holds without tracing every function it was passed to. Mutable values require you to consider everything that might have modified them, and that reasoning cost grows with the size of the codebase.
No spooky action at a distance. Passing a mutable object to a function that modifies it produces changes the caller did not expect — one of the most common sources of subtle bugs, particularly when the modification is incidental to the function's purpose.
Thread safety is automatic. Data races require concurrent writes. If nothing can be written, immutable data can be shared freely across threads with no locks. This is a substantial simplification and a major reason immutability is central to concurrent and functional programming.
Cheap change detection. If a value is never modified in place, reference equality is sufficient to detect change — you compare pointers rather than contents. This is exactly why React's rendering model and state libraries depend on immutable updates, and why mutating state in place causes re-renders to be missed.
Easier debugging, undo and time travel. Keeping previous versions costs nothing extra, since they were never overwritten.
Safe caching and memoisation, since a key cannot change underneath you.
The costs, honestly:
Allocation. Creating new values rather than mutating generates garbage. Persistent data structures mitigate this by sharing unchanged parts rather than copying wholesale, which makes the cost far smaller than it appears.
Verbosity in languages without good support for it.
Genuinely hot loops may need mutation for performance — a local, contained exception.
Watch for shallow immutability. Freezing an object does not freeze nested objects, which catches people out.