Re: Review my code - delay-map

2011-11-18 Thread Chris Perkins
Meikel,

That's very helpful. You and I took essentially the same approach - wrap a 
real map and delegate most operations to it. You used deftype, which I 
was afraid to try because there seemed to be too many interfaces and too 
many methods to implement, so I used proxy and APersistentMap to get some 
of it for free. I see from your code that there aren't nearly as many as I 
had feared.

Your code has helped me to answer most of the questions I had.

Thanks,

- Chris

-- 
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

Re: Review my code - delay-map

2011-11-18 Thread Meikel Brandmeyer (kotarak)
Hi,

glad it helped. There are still intresting questions. For example 
transients. It'd sure be interesting to have this also.

Meikel

-- 
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

Review my code - delay-map

2011-11-17 Thread Chris Perkins
I'm trying to implement this: I want an object that behaves just like a 
normal clojure map, except in one very specific case - if a value is a 
Delay, then getting that value out of the map will force it.

Other than that one difference, it should be indistinguishable from a 
regular map (or as close to indistinguishable as is reasonable).

After some false starts, I have most of an implementation.

(defn delay-map
  Wraps the given map such that any value that is a Delay will be
  forced when extracted.
  [ [m]]
  (proxy [clojure.lang.APersistentMap
  clojure.lang.IObj
  clojure.lang.IEditableCollection] []

;; This method implements the real funtionality:
(valAt
  ([k] (force (get m k)))
  ([k not-found] (force (get m k not-found

;; These methods are to preserve the type by returning
;; new delay-map instances when required.
(assoc [k v]
  (delay-map (assoc m k v)))
;;(assocEx [k v] ???)
(without [k]
  (delay-map (dissoc m k)))
(withMeta [md]
  (delay-map (with-meta m md)))

;; boilerplate - just delegate:
(containsKey [k] (contains? m k))
(count [] (count m))
(entryAt [k] (.entryAt ^clojure.lang.Associative m))
(iterator [] (.iterator ^java.util.Map m))
(meta [] (meta m))
(seq [] (seq m))

(asTransient []
  (throw (Exception. I don't know how to implement this yet.)))
))


I also made a couple of macros to help out:

(defmacro lazy-map [ keyvals]
  (when (odd? (count keyvals))
(throw (Exception. lazy-map requires an even number of forms)))
  (list
   `delay-map
   (into {}
 (for [[k v] (partition 2 keyvals)]
   [k (if (and (list? v) (symbol? (first v)))
(list `delay v)
v)]

(defmacro lazy-assoc [m  keyvals]
  `(delay-map (merge ~m (lazy-map ~@keyvals


This mostly seems to work they way I want:

user (def m (lazy-map :normal-value hello
   :delayed-value (do (println working...) 
(Thread/sleep 2000) hi)))
#'user/m
user m
{:normal-value hello, :delayed-value #Delay@10e284f: :pending}
user (:delayed-value m)
working...
hi
user (:delayed-value m)
hi


Now, my questions are:
1) Does proxy seem like the right way to do this (as opposed to reify, 
etc.)?
2) What is assocEx (from IPersistentMap), and do I need to implement it?
3) Any idea how I could implement asTransient (or whether I should)?
4) Is there a way in clojure to find out what methods are abstract in a 
class (i.e. APersistentMap)? I struggled for a while trying to figure out 
which methods I needed to write - eventually I just had Eclipse generate a 
java class for me with method stubs.
5) Most importantly: good idea? bad idea? If so, why? Are there any holes 
in this that I'm not seeing. Are there ways that a user could accidentally 
turn a delay-map into a regular map (I know of one: (into {} my-delay-map))?


Finally, in case you're wondering why I want this: I was reading through 
the code of a large, complex web application, and I realized that there are 
two competing forces at work when considering performance:
1) If there is data that you will need in several places, you want to avoid 
calculating it repeatedly.
2) If there is data that you will not need at all, you dont' want to 
calculate it at all.

Take session-state as an example. Suppose there is a session-store library, 
and as a consumer of it I have to call a function, say (get-session), when 
I want to use it. Maybe I end up calling that function in half-a-dozen 
places. That's wasteful. So I do the smart thing and use Ring middleware 
that loads the session only once and adds it to the request map. Then I can 
pull it out when I need it, and it's only loaded once. But what if I never 
need it for a particular request? Then I have loaded it for nothing.

In other words, point 1 above encourages us to put stuff in the map 
pre-emptively, and point 2 encourages us not to.

If the request map was a delay-map, then session state could be loaded 
exactly one time or zero times, as required, transparently to the consumer. 
Existing code that extracts :session from the request would still work, but 
now code-paths that do not use :session do not pay the cost of loading it.

Anyway, that's just the example that motivated the idea. Whether it turns 
out to be useful in practice remains to be seen.


thanks,

- Chris Perkins



-- 
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

Re: Review my code - delay-map

2011-11-17 Thread Meikel Brandmeyer
Hi,

without looking too much at your code, I might suggest you have look at my lazy 
map library: http://bit.ly/vNA56f. It basically solves the same problem. You 
can compare your solution to mine. If you want to discuss anything, feel free 
to go ahead.

Sincerely
Meikel

PS: It's also on clojars as de.kotka/lazymap. The lazymap was already taken. :/

-- 
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