开发者

Ref to map vs. map to refs vs. multiple refs

I'm working on a GUI application in Swing+Clojure that requires various mutable pieces of data (e.g. scroll p开发者_运维问答osition, user data, filename, selected tool options etc.).

I can see at least three different ways of handling this set of data:

Create a ref to a map of all the data:

(def data (ref {
  :filename    "filename.xml" 
  :scroll      [0 0] }))

Create a map of refs to the individual data elements:

(def datamap {
  :filename    (ref "filename.xml") 
  :scroll      (ref [0 0]) }))

Create a separate ref for each in the namespace:

(def scroll (ref [0 0]))    

(def filename (ref "filename.xml"))

Note: This data will be accessed concurrently, e.g. by background processing threads or the Swing event handling thread. However there probably isn't a need for consistent transactional updates of multiple elements.

What would be your recommended approach and why?


Firstly, if you end up using either just one piece of mutable state or several independent pieces (independent as in "it makes no sense to ask whether one is consistent with another"), why not go with Atoms rather than Refs? That's a pretty significant reduction of overhead, which might actually matter if you make a lot of updates.

Secondly, storing filename, scroll position etc. in separate Refs (but not Atoms) is fine as long as you design your transactions carefully (i.e. all relevant Refs need to be mentioned, some might need to be ensured etc. -- basically the transaction must be sure to fail if inconsistent state were to arise). Careful design of such transactions might be a waste of effort if you're managing GUI state most of which hardly ever changes (besides scroll position and buffer contents, what is actually likely to change frequently? -- I mean that's something to consider seriously, as the answer should determine the final design). There's any number of scenarios where having multiple reference type objects is preferable to having one, I'm just not sure that managing basic GUI state is one of them. :-)

Note that performing updates to nested structures held in reference type objects is very clean in Clojure, e.g. (using an Atom):

;; assuming that state-o-matic is an Atom which holds a map,
;; which holds the key of :foo, with which a vector is associated,
;; whose first item is another vector, whose first item is a map
;; which holds the key of :bar associated to a number,
;; the following increments said number
(swap! state-o-matic update-in [:foo 0 1 :bar] inc)

See also get-in & assoc-in.


If there are no concurrency - then there are no difference, you know.

But if it can be used from different threads, then first case will be better. Because it guaranties you a consistent state.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜