On Thu, Feb 19, 2009 at 11:34 AM, mikel <mev...@mac.com> wrote:
>
> I did consider it, and am still considering. I'd be interested to know
> other people's opinions about the best (that is, most comfortable for
> users, least out-of-place) way of providing GFs in library code.

I'm not your target audience for that question, but you bring up some
other interesting questions as well...

> I could certainly implement GFs by making make-generic-function return
> an AFn proxy. A  disadvantage of doing that (and of reoresenting GFs
> as closures, as the first implentation did) is that a generic function
> object then has no identity as such; that is, you can't tell from
> looking at it that it's a generic function. It's some AFn proxy (or
> closure) that might be anything. If you want to know whether it's a
> gf, you just have to try using it as one and see what happens.

On this point, would it help if you could provide a custom print for
the object?  This idea has come up a couple times now, and I have a
toy implementation that seems indicate it could be done cleanly.  It
would allow your make-generic-function to return an object that would
print uniquely, with whatever combination of name and closed-over data
you want, independant of the specific proxy class that its an instance
of.  Of course calling 'class' on it would still show the goofy proxy
class name, but I wouldn't expect that to be a big problem.

> Another disadvantage is that, like MultiFns, generic functions have
> some state. In both cases, the state is a dispatch table. The dispatch
> algorithm used is different for the two types of polymoprhic
> functions, but both carry around data used by dispatch, and both sort
> of want you to be able to update the state (in the case of MultiFn, by
> calling defmethod). You kind of want to have an equivalent for generic
> functions of defmethod, and of add-method and remove-method.

You can close over an atom or ref to get your mutable state.  This is
a mess and by itself useless, but maybe it helps show what I mean:

  (defn make-thing [a b]
    (let [state (atom {})]
      (proxy [clojure.lang.AFn clojure.lang.IDeref] []
        (deref [] state)
        (invoke
          ([] "no arg")
          ([x] "one arg")))))

  (def thing (make-thing 1 2))

Now you can call the thing with zero or one args:

  user=> (thing 1)
  "one arg"

You can also write functions that mutate it's state.  A add-method
function could be defined to do something like:

  (swap! @thing assoc :A 1)

That new value can be accessed from any of the invoke bodies, or
anywhere else, actually:

  user=> thing
  #<afn$ide...@2a6ff: #<a...@21d23b: {:A 1}>>

That prints ugly indeed.  Rich, do you have any interest in per-object
custom print fns, hanging off meta-data?

> I'd be interested in opinions about what the best approach is and why.

I can't say with confidence what the best approach is, I just know
that much prefer the dynamic nature of proxy and when possible would
rather use it.  Perhaps what I outlined above is too convoluted for
your taste, and I think that would be a reasonable response.  I mostly
want to make sure proxy is not overlooked.

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