6 ms·
It's missing my favorite concurrency construct: immutable, persistent data structures. I was initially interest in Clojure for things like STM, but found most
by bcrosby95 7y ago
It's missing my favorite concurrency construct: immutable, persistent data structures. I was initially interest in Clojure for things like STM, but found most of my concurrency problems are amenable to immutable data. You can certainly use this technique in other languages, but it tends to be higher effort.
- kubanczyk 7y agoNo. Immutable structures still require locking. If you are spending 100 ms calculating the new version of the immutable structure, you want to make sure that the nearby thread isn't making their own version. You don't want any of the two results silently overwritten. You want the nearby thread be sequential - to wait for you and base on your result.
- Scarbutt 7y agoIf he's talking about multithreading he probably wanted to say immutable data structures in combination with clojure's atom (CAS semantics).
- deleted 7y ago[deleted]
- dpratt71 7y agoThis is not how persistent data structures are used in practice. There is no "the" new version of a persistent structure. The best analogy I can think of is to compare it to a VCS (e.g. git). There is no need to lock any existing commit in order to create a new commit (which together with prior commits, represents a new version of the code).
- majormajor 7y agoI'm not familiar with Clojure, but you can hit conflicts in the Git world, though, which seem to be what the parent is concerned about. Two of us could be creating some new data based on the last data we had, at time T, and then the other person submits theirs at time T+5, and I submit mine at time T+10. In that case, my change hasn't taken theirs into account.
- escherize 7y agoIf you can "submit" your change back to the original datastructure then the original datastructure is not immutable, right? Here's a nice explaination about how the persistant immutable datastructures work: https://hypirion.com/musings/understanding-persistent-vector-pt-1 https://hypirion.com/musings/understanding-persistent-vector...
- setr 7y agoI believe the question is that, if two threads take the same immutable vector, and both make a change to it independently, they'll end up with two new vectors (eg two branches in git); a vector that reflects thread1's change, and a second vector that reflects thread2's change. So now you have a conflict, which requires resolution; git has a human intervene. eg x = [1,2,3] Thread1 -> x + [4] => [1,2,3,4] Thread2 -> x + [5] => [1,2,3,5] But you were expecting [1,2,3,4,5] Reality was that you wanted an order to your events, normally enforced by locking, which the immutable vector doesn't seem to help you with; they were both able to update independently, but you actually wanted them to update dependently. If you try to use immutable datastructures to avoid locking, then how is conflict resolution handled? I think the answer would be that it doesn't help you avoid locking; either you lock & share a single reference to the latest version of your immutable vector, to enforce ordered events, or you define a resolution strategy separately. The immutability aspect just stops you from not having a resolution strategy -- which would always be incorrect And if I understand correctly, the ideal scenario for immutable datastructures in concurrent scenarios is when you can define such a merge strategy (and safely give threads their own copy of the datastructure to muddle with, without actually having to copy the entire datastructure)
- dpratt71 7y agoYou could, as per your example, use locking as part of a resolution/merge strategy to combine the results of two separate computations running on two separate threads. Or you could use some strategy that does not involve locking. Either way, it does not support the original claim I disputed that "Immutable structures still require locking".
- samatman 7y agoPlease read the first paragraph of this page and see if your objection still stands: https://clojure.org/about/concurrent_programming https://clojure.org/about/concurrent_programming
- reitzensteinm 7y agoClojure generally uses CAS semantics, although it also has transactions that can update multiple refs atomically. So nothing is ever "silently overwritten" and there's no locking required, it's all optimistic concurrency. However, to agree with part of your point, an atom being updated with CAS can only ever progress linearly; if you bang 8 threads in a loop trying to update it, you might as well use a lock, because 7/8 of the work is going to be thrown out. They should only be used for cases where on average one thread or less is working on updating it; anything more, and it needs to be split, the problem rethought, or some mechanism for not throwing out wasted work implemented. It's not a silver bullet.
- Scarbutt 7y agoOnce javascript gets immutable types and better handling of objects, the gap between it and clojure will very small for most daily tasks. https://github.com/tc39/proposal-record-tuple https://github.com/tc39/proposal-record-tuple https://github.com/tc39/proposal-object-iteration https://github.com/tc39/proposal-object-iteration
- fnordsensei 7y agoIt’s not only about having immutable constructs available, but having immutability as default, and pervasive throughout the ecosystem.
- adamkl 7y agoThe issue that I find with JavaScript (which I use on a daily basis) is that it has become a "kitchen-sink" language. Every time it gets new additions to "close the gap" with some other language, it gains more ways to do the same things. A big thing with Clojure is that it tries to provide a single, idiomatic way of doing things (though overuse of macros may cloud this picture at times). Generally, you can hop into any Clojure codebase and very quickly understand what's what. Since JavaScript can do just about anything (functional, imperative, object-oriented, prototypical), there's no one "true" way of writing code, so while its possible use the "good parts" of JavaScript, everyone seems to have a different idea of what those are. Flexibility can be a virtue, but I find myself preferring Clojure due to the constraints it provides.