3 ms·
I'm not an expert in Clojure or Rust, but an interested outsider in both, so please don't take my question as a challenge but a genuine curiosity: Doesn't the
by widdershins 2y ago
I'm not an expert in Clojure or Rust, but an interested outsider in both, so please don't take my question as a challenge but a genuine curiosity:
Doesn't the focus on immutable data make most of the ownership stuff redundant? My understanding was that ownership lets you be sure that you're the only mutable owner of a resource, or otherwise that you share the resource immutably. If data is (almost) always immutable, which seems to be a founding principle of Clojure, then what does ownership/borrowing buy you?
- oldpersonintx 2y ago[dead]
- j-pb 2y agoI 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.
- lincpa 2y ago[dead]
- mrkeen 2y ago> If data is (almost) always immutable, which seems to be a founding principle of Clojure Being immutable isn't some "best-practice" like eating your veggies, where the more you eat, the healthier you are, and occasional sugar is OK. I either can reuse the result of getFoo() or I can't. If getFoo() is 99% immutable - as the caller, it's my job to consider taking locks and/or making defensive copies. If I want to publish library code that calls getFoo(), now my callers will need to consider taking locks and/or making defensive copies. Your question was about Rust ownership, and I answered about Haskell immutability - but they're both the same in that they're pretty strict compiler rules, and you have to stray into unsafe territory to violate them.
- 2mlWQbCK 2y agoI am not sure where "almost" came from. Data in Clojure is 100% immutable? You can pass around data between functions or between threads and never worry about anyone modifying it. I believe Clojure is less strict about I/O than what Haskell is(?), but once some data has been created it can not be modified. Any modification will return a new thing, never modify the original thing. Java interop breaks things of course, much like unsafe Rust breaks guarantees of that language.
- mrkeen 2y agoGiven some Clojure function getFoo() which only calls into the Clojure std lib, and doesn't call any function with 'unsafe' (or similar) in the name, is it always true that: getFoo() = getFoo()
- 2mlWQbCK 2y agoFunctions are not always pure, no. Clojure is not so strict about I/O, meaning that function could for instance call out to make a database request. But I think that is unrelated to immutability or ownership of data? Immutability guarantees if I call getFoo(x) I can trust that nothing happens to x (assuming x is proper Clojure data and not some unsafe other thing like a Java Object). And getFoo can likewise return anything without there being any risk that anyone else modifies that thing. It does not matter who owns x or who owns the return value from getFoo, since no one is able to modify those things anyway. * Database request was a bad example as, as far as I know, there is nothing built-in for supporting that, so that would already be in unsafe Java territory. But there are non-pure functions built into the Clojure standard library that getFoo could call to return different results on the same input, like slurp or deref, and probably many other ones (I have not used Clojure for a long time).