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

Reply via email to