Git and bcachefs work the same way, btw: you never really change to anything, you just make a new version (that shares most of its storage with the previous version), and then at the end update a pointer.
Making a 'copy' in these systems is basically O(1), but making updates might cost you O(log n) (details depend on the data structure in question, some can do O(1)), and in general you want some form of garbage collection, or some type system that really cares about tracking these kinds of thing statically; think something like Rust's borrow checker on steroids.
> Not sure what the language has to do with it, you'd have to do the same in any language, explicitly or implicitly.
If instead your language or system encourages mutation, then making a complete O(n) copy of your state is the easiest way to get the desired behaviour.
As a random tangent, whilst memcpy in the general case is going to be O(n) given that in this program the n is a fixed size the operation in context is always going to be O(1). Fundamentally though it's not a very good way to compare the performance profiles of the approaches to this problem on real hardware.
Well, with a fixed n, every operation trivially becomes O(1).
> This isn't really trying to emulate copy-on-write though. It's intentionally making a copy temporarily to mutate it further whilst keeping the original ready to be mutated on the next tick. They share superficial similarity but that's about it.
Having to copy everything is exactly what you need to achieve this effect, when you don't have copy-on-write. You need to make a copy somewhere. (Or otherwise, explicitly roll-back any changes you made.)
Right, but still, that's an implementation detail. It could have been implicit, or it can (like in the authors case be explicit), how is that important?
I'm well aware of languages that does this implicitly, as I'm mostly writing Clojure code which is all about immutability and persistent data structures. I still don't understand why you want to highlight that this could be implicit instead of explicit, what the author had to do wouldn't change really.
They're doing a duplicate of the state not because it's required in the language or whatever, but because they want to predict something without affecting the actual state. The only way of doing that is running the actual code against a new state duplicate from the existing, actual state.
Not sure what the language has to do with it, you'd have to do the same in any language, explicitly or implicitly.