Lets look at the upd function that is part of the map benchmark I posted 
above...

(defn upd [m i]
  (let [m1 (assoc m i (- i))
        bb (ByteBuffer/allocate (lazy-byte-length m1))]
    (lazy-write m1 bb)
    (.flip bb)
    (load-aamap bb)))


And its invocation...


(def lazy-m (reduce upd lazy-map (range updates)))


Here we see that upd is called repeatedly by the reduce, its first argument 
being the result of the previous call to upd.


m1 (assoc m i (- i)


The above is in the upd function. It uses assoc to create an updated copy of 
the map.


bb (ByteBuffer/allocate (lazy-byte-length m1)


bb is a byte buffer with a capacity equal to the length of the serialized 
contents of m1.


    (lazy-write m1 bb)
    (.flip bb)
    (load-aamap bb))


Now we write the updated map to the byte buffer, flip it, and then create a new 
map from the byte buffer. This new map is then passed back to the reduce method 
which calls upd again with the new/updated map.


This usage, being a benchmark, is a bit atypical as we are serializing the 
contents of the map with each update and then loading the result back into a 
new map. But. You can see that the map works like the standard clojure map, and 
only it works additionally with the lazy-byte-length, lazy-write and aamap-load 
functions. The underlying tree is not normally accessed by the application 
developer, just as the red/black tree used to implement clojure sorted maps are 
not normally accessed by the application developer.


So aamap is used just like sorted-map, except for the additional capability of 
being able to quickly load it from and write it to a ByteBuffer. And, like a 
sorted-map, you can also specify a comparator for ordering the keys, though the 
comparator would be passed in the optional opts map on the aamap-load function 
or in the create-lazy-aamap function.


The full API is given here: 
https://github.com/laforge49/aatree/blob/master/src/aatree/core.clj (Still need 
to add doc strings though.)




On Thursday, October 1, 2015 at 6:15:06 PM UTC-4, Nathan Davis wrote:
>
> Thanks, that really helps clarify things.  So is the new tree saved when 
> it is created (i.e., when the old tree is "updated"), or do you have to 
> "write it back" at some point?  In other words, as a user of aatree, do I 
> obtain a new tree and then tell aatree "Here is a new tree.  Please 
> (incrementally) save it."  Or does the mere fact that I have a new tree 
> mean that it has already been saved?
>
> As for terminology, I wouldn't worry too much about using the word 
> "update" when talking about immutable datastructures.  Most functional 
> programmers understand the term "update" to mean "make a 'copy' of 
> something, with some part of it changed in some way" in such contexts.  I 
> think what was confusing is that (a) the Readme didn't explicitly say 
> aatrees were immutable (from a value perspective) and (b) there aren't any 
> examples on using the library.  I think adding a few examples (with perhaps 
> a little explanation of what is happening under the covers) would go a long 
> way.
>
> Nathan Davis
>
> On Thursday, October 1, 2015 at 4:22:48 PM UTC-5, William la Forge wrote:
>>
>> Sorry for my bad language. I've not written much about immutable 
>> structures before so old phraseology keeps coming in inappropriately.
>>
>> The structures are immutable. A change results in a new tree with only 
>> the nodes which are changed (and their parent nodes) replaced. But the key 
>> property here is that deserialization and serialization operations which 
>> are performed on these trees are done in place, without making any new 
>> nodes--thanks to the magic of atoms. So for example, if several threads are 
>> accessing the same tree instance, they all share the deserialized values 
>> while any changes to the tree contents results in new tree instances. I.E. 
>> It is done right, to the best of my ability. (Extra eyeballs on the code 
>> always being appreciated, of course!)
>>
>> Now I'm sorry for having been so terse and ambiguous. I need practice 
>> talking about this stuff. So your questions are appreciated twice over! :-) 
>>
>>
>> On Thursday, October 1, 2015 at 4:41:33 PM UTC-4, Nathan Davis wrote:
>>>
>>>
>>>
>>> On Thursday, October 1, 2015 at 2:58:15 PM UTC-5, William la Forge wrote:
>>>>
>>>> A value can have more than one form or implementation. For example, a 
>>>> String and a char array may both represent the same value. Most objects, 
>>>> for example, can be serialized. Changing the form of a value then is not a 
>>>> change of value. This is the idea behind lazy deserialization / 
>>>> reserialization.
>>>>
>>>>
>>>> We can represent a data structure as a tree, where the values in the 
>>>> tree can be either the immutable value of the object or a read-only 
>>>> ByteBuffer holding the serialized form of the value, or both. Both forms 
>>>> can be held by nodes using atoms, so the form of the values can be changed 
>>>> without having to create a new tree. The value remains unchanged and the 
>>>> tree can be safely shared between threads.
>>>>
>>>
>>> I think we are on the same page to this point. 
>>>  
>>>
>>>> Lazy deserialization comes after loading a map or vector from a 
>>>> ByteBuffer. Initially only the root exists, which holds only the 
>>>> ByteBuffer. As you access and alter the contents of the map or vector, the 
>>>> portions of the tree which are accessed are deserialized.
>>>>
>>>
>>> This is where I get confused.  Are aatrees persistent structures (in the 
>>> functional programming sense, like Clojure's data structures) whose values 
>>> cannot be changed (although their internal representation ("form") may 
>>> change), or are they mutable?  If they are persistent, what do you mean by 
>>> "alter the contents"?
>>>  
>>> Nathan Davis
>>>
>>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to