I gave a long-ish answer to a sibling comment, that maybe sheds some light on that question, but I'll try to also give a concrete example where ownership complements immutability. (You best read that response first before continuing here.)
You are right in that immutability or more precisely the persistence that copy-on-write brings somewhat solves many of the issues that ownership also solves.
Persistence allows you to not care as much about who owns what, because whenever something is modified it is simply copied (with structural sharing), so you know that whatever you have is local anyways, not because you are the only one who has exclusive access to the thing, but because you make a copy of it at the point where answering that question would matter.
But you miss out on two things from that:
- Performance: Those copies are cheap but not free. Borrowing complements _persistent_ immutability in that regard extremely well, because it allows you to check if you're currently the only one using something and modify it mutably in that case. Clojure has a concept called transients, where you create an intermediately mutable version of an immutable thing to perform batch updates, but you still have to manage that yourself, with ownership it happens magically behind the scenes.
- Exclusive types: The other comment I wrote contains an example of this. I have an `ExclusiveID` type in my Database that is similar to a `row_id`. I can recover a lot of the capabilities of transactions and software transactional memory from these, simply because a user can rely on `ExclusiveID`s existing only at a single point at a time in their code. And `ExclusiveID` itself is a completely immutable thing, but the "contract" on how it can be used is what makes it powerful.
Immutability on a domain logic level also does not help you when it comes to dealing with inherently immutable things like devices and networks, whereas ownership does.
So I would argue that those two concepts are complementing each other extremely well, both implementation wise, but also in terms of a the mental model of how your code works.
You are right in that immutability or more precisely the persistence that copy-on-write brings somewhat solves many of the issues that ownership also solves.
Persistence allows you to not care as much about who owns what, because whenever something is modified it is simply copied (with structural sharing), so you know that whatever you have is local anyways, not because you are the only one who has exclusive access to the thing, but because you make a copy of it at the point where answering that question would matter.
But you miss out on two things from that:
- Performance: Those copies are cheap but not free. Borrowing complements _persistent_ immutability in that regard extremely well, because it allows you to check if you're currently the only one using something and modify it mutably in that case. Clojure has a concept called transients, where you create an intermediately mutable version of an immutable thing to perform batch updates, but you still have to manage that yourself, with ownership it happens magically behind the scenes.
- Exclusive types: The other comment I wrote contains an example of this. I have an `ExclusiveID` type in my Database that is similar to a `row_id`. I can recover a lot of the capabilities of transactions and software transactional memory from these, simply because a user can rely on `ExclusiveID`s existing only at a single point at a time in their code. And `ExclusiveID` itself is a completely immutable thing, but the "contract" on how it can be used is what makes it powerful.
Immutability on a domain logic level also does not help you when it comes to dealing with inherently immutable things like devices and networks, whereas ownership does.
So I would argue that those two concepts are complementing each other extremely well, both implementation wise, but also in terms of a the mental model of how your code works.