This is nothing short of amazing for those who want to build ad-hoc type
systems.
(defstruct #^{:type ::my-struct} my-struct :a :b)
(type #'my-struct) ; -> :user/my-struct!

I have a lot of code fixing to do now :)

Also Konrad's point that using multimethods for dispatch-fns would be ugly,
but actually I think this actually works out well!

(defmulti multi-dispatch type)
(defmethod multi-dispatch ::my-type [x]
  (:tag x))
(defmethod multi-dispatch ::another-type [x]
  (:protocol x))

(defmulti my-multifn multi-dispatch)
(defmethod my-multifn ::some-tag
  [x]
  (print "An object!"))
(defmethod my-multifn ::some-protocol
  [x]
  (print "A protocol"))

(my-multifn #^{:type ::my-type} {:tag ::some-tag}) ; -> "An object!"
(my-multifn #^{:type ::another-type} {:protocol ::some-protocol}) ; -> "A
protocol!"

Amazing.

On Wed, Feb 25, 2009 at 7:51 PM, Rich Hickey <richhic...@gmail.com> wrote:

>
>
>
> On Feb 25, 12:19 pm, Konrad Hinsen <konrad.hin...@laposte.net> wrote:
> > On Feb 25, 2009, at 17:40, David Nolen wrote:
> >
> > > Should print and println be multimethods? It seems the ability to
> > > custom print a data structure would be generally useful.
> >
> > It's already there, just not documented as far as I know. All the
> > printing routines end up calling clojure.core/print-method and
> > clojure.core/print-dup, which are multimethods dispatching on class.
> >
> > > Not totally following here, looking at your code... Pardon my
> > > slowness but why not dispatch on :tag first, and class if no :tag?
> >
> > That's possible, of course, but the result is a multimethod that
> > works for (a) class-based types and (b) one specific type hierarchy
> > hard-wired into the selector, such as your :tag. If I write some
> > other type system, it won't fit in. That makes it impossible to
> > define truly general interfaces that are open for anyone to implement.
> >
> > Take print-method in clojure.core as an example: How would you
> > implement its selector, such that anyone could plug in their type
> > system based on some tagging scheme? Perhaps one could come up with a
> > scheme in which the selector function is itself a multimethod, but
> > that would probably be quite messy.
> >
> > > Tags of course should be namespaced so is this really that much of
> > > an issue in practice? Since tags are keywords they don't have the
> > > interning conflict problem that symbols of the same name generally
> > > do, right?
> >
> > Right. Namespaced tags go a long way to avoid name clashes. However,
> > they are still not the private property of any one library module.
> > Your namespaced tag is an object that can end up in any data
> > structure, intentionally or by error. Only time will tell if this is
> > a problem in practice.
> >
> > Anyway, my two main arguments in this issue are printing and open-to-
> > anyone interfaces with multimethods. These are the problems that I
> > had in my own code and that I wanted to solve. Printing is important
> > for complex nested data structures and interactive use. Generic
> > interfaces are a very nice feature to have. I came across this
> > problem twice:
> >
> > 1) In clojure.contrib.accumulators. Ideally, it should be possible to
> > implement additional accumulator types elsewhere, using the same
> > interface. With the current implementation based on meta-data, that
> > is possible, but only for data types that allow meta-data. It is thus
> > not possible to build accumulators based on Java classes, at least
> > not without wrapping them in a map or vector. Moreover, the selector
> > function, based on meta-data with a fallback to classes, is neither
> > elegant nor efficient, and much of the code in the library deals with
> > the meta-data tagging scheme rather than with its real job.
> >
> > 2) In clojure.contrib.streams-utils. Again, I wanted to define a
> > generic interface to data streams. At the moment, it uses a
> > multimethod dispatching on class, but that doesn't leave much room to
> > define different data stream sources. That was in fact what prompted
> > me to write the types library.
> >
>
> You raise interesting issues and I'd like to explore them further. I'm
> not sure the issues you have with type-tag-or-class dispatch are all
> that prohibitive. In any case, I've added a type function that returns
> the :type metadata or the class if none:
>
> user=> (type #^{:type ::Fred} [1 2 3])
> :user/Fred
>
> user=> (type "foo")
> java.lang.String
>
> which should help people standardize.
>
> If you want to multiplex multimethods for your ADT type, you can just
> define a single :type ::ADT, and then sub-dispatch on e.g. :adt-type.
>
> I'm not sure the mechanism you are using (actual Class types) allows
> for any more overloading - Class is a single slot too, after all.
> Interfaces offer some mixin potential, but they can't be superimposed
> on existing classes. The same mixin capabilities of interfaces are
> available for type tags, just say;
>
> (derive ::my-type :freds/interface)
> (derive ::my-type :ethels/interface)
>
> etc.
>
> The trick here is that you *can* superimpose such tags on existing
> classes:
>
> (derive String :freds/interface)
>
> A bigger problem with the mechanism you've chosen is its dependence on
> some implementation details. I haven't promised, e.g. that every fn
> generates a unique class type.
>
> Also, there may be issues on re-evaluation - it's not necessarily
> going to yield the same classes.
>
> Rich
>
> >
>

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