On Fri, Jan 2, 2009 at 1:30 AM, Tom Faulhaber <tomfaulha...@gmail.com> wrote: > > (This is sort of a follow-up to this thread from last July: > http://groups.google.com/group/clojure/browse_thread/thread/7f5cf3e78954b81d/aae7f082c51337c9?lnk=gst&q=proxy#aae7f082c51337c9.) > > Recently, I've been building a version of java.io.Writer > that knows what the current column is on the output so it > can handle tabs, etc. > > It would be pretty easy to do this with AOT, :genclass, > etc. and just have a ref to the column number in my state, > but life seems easier if you don't have to use AOT, so I > considered doing it with a proxy. > > However, proxies *only* support the methods provided by > their super- classes. They do this so that the proxy class > can be compiled once, making proxy intances and variation > super-cheap.
I much prefer using proxy over gen-class when at all possible, and so far I've had a lot of success. For state especially, closures are usually sufficient. Here's an example of a proxy that maintains state in a local mutable object. In this case it's a StringBuilder -- in other cases a ref might be more appropriate: (import '(java.io LineNumberReader FileReader PushbackReader)) (with-open [rdr (LineNumberReader. (FileReader. "test.clj"))] (let [text (StringBuilder.) pbr (proxy [PushbackReader] [rdr] (read [] (let [i (proxy-super read)] (.append text (char i)) i)))] (read (PushbackReader. pbr)) (str text))) This is based on code from clojure.contrib.repl-utils. I know I mentioned this to you in IRC, but I thought I should bring it up here for the benefit of others. In a lot of cases this kind of usage is sufficient. Your objection was, I believe, that you wanted to return the proxy object from your function, but allow users of it to access the state. As I suggested at the time, this can be done by returning a Clojure collection (probably a map) instead of the bare proxy object, and having the state live in there. This has all the benefits of Clojure persistent, as well as allowing for more than a single state field. This might look something like: (defn make-my-obj [] (let [my-state (ref 0) obj (proxy [BaseClass] [] ...)] {:my-state my-state, :obj obj})) This would give you sufficient structure to add as much state as you want. If you need ways to directly manipulate that state, rather than going through the :obj, you could add functions to the hash as well that by closing over the same state could act as methods. Something like: ((:set-my-state my-obj) new-state) Of course these could be wrapped in regular functions as well get a more idiomatic api. Finally, if this is just too clumsy, I would still prefer gen-interface over gen-class. This would allow you to declare all the state-manipulation and -access methods you'd need. Then you could use 'proxy' and close over any state objects you need, returning the base proxy object. --Chouser --~--~---------~--~----~------------~-------~--~----~ 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 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 -~----------~----~----~----~------~----~------~--~---