Skip to content

Instantly share code, notes, and snippets.

@hutch
Created December 6, 2009 19:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hutch/250364 to your computer and use it in GitHub Desktop.
Save hutch/250364 to your computer and use it in GitHub Desktop.
Question, answered, on how to dispatch a multimethod in Clojure based on a deftype
[ a link to the whole thread: http://tr.im/GRyQ ]
Hi,
I'm new to Clojure, not new to lisp (CL and scheme), and having a
thoroughly good time. I've been having a go at the new deftype stuff
and using a clone of the new branch from the git repository (up-to-
date as of this message being posted). So far everything I've tried
has worked very nicely, except for one thing.
I've put three files up as a gist: http://gist.github.com/250364 that
illustrate (I hope) my question.
So. I've defined a type 'Foo -- inevitably foo, sorry -- and I want to
define a very simple multimethod that dispatches on the class of its
single argument. I understand that defmethod needs a fully ns
qualified name to dispatch properly. I was hoping there was a shorter
way of doing this than play.foo.Foo, maybe using some sort of alias-
based technique like those in Stuary Halloway's book (p233 and
thereabout).
I've got six variations in there, and I know full well that most of
these should not work, but I put them in anyway.
I believe that I'm AOT compiling everything (I'm compiling the ./src/
play/foo.clj file and the class files are on disk, so...)
It turns out that dispatching on play.foo.Foo is the only way that
works. I was hoping ::f/Foo or f/Foo would work too (maybe my alias is
wrong??). Especially since, with aliasing in the user namespace, I can
create a play.foo.Foo using f/Foo
Obviously, I have a workaround, but that's going to get ugly fast with
a real namespace name, not to mention making re-naming the namespace
harder than it should be.
If someone could help me out I'd appreciate it.
Thanks,
Bob
; Requires the clojure new branch because it is using the new deftype
(ns play.foo)
(alias 'f 'play.foo)
(deftype Foo [a]
:as this
clojure.lang.IPersistentMap)
(defmulti foo-print class)
(defmethod foo-print :default [thing] (println (format "don't know how to foo-print a %s" (class thing))))
(defmethod foo-print ::f/Foo [foo] (println (format "::f/Foo %s" (.toString foo))))
(defmethod foo-print ::f.Foo [foo] (println (format "::f.Foo %s" (.toString foo))))
(defmethod foo-print f/Foo [foo] (println (format "f/Foo %s" (.toString foo))))
(defmethod foo-print ::Foo [foo] (println (format "::FOO %s" (.toString foo))))
(defmethod foo-print ::play.foo/Foo [foo] (println (format "::play.foo/Foo %s" (.toString foo))))
(defmethod foo-print play.foo/Foo [foo] (println (format "play.foo/Foo %s" (.toString foo))))
(defmethod foo-print play.foo.Foo [foo] (println (format "play.foo.Foo %s" (.toString foo))))
(foo-print (Foo "foo in foo.clj"))
user=> (load "go-foo")
play.foo.Foo play.foo.Foo@127028e5
make them...
x1: play.foo.Foo@a5995ff4
x2: play.foo.Foo@a5995e35
x3: null
x4: null
x5: play.foo.Foo@a5995cef
foo-print them...
play.foo.Foo play.foo.Foo@a5995ff4
play.foo.Foo play.foo.Foo@a5995e35
don't know how to foo-print a null
don't know how to foo-print a null
play.foo.Foo play.foo.Foo@a5995cef
; this file is really src/play/foo.clj (I changed the name to keep the gist happy)
(ns play.foo)
(deftype Foo [a]
:as this
clojure.lang.IPersistentMap)
; The issue is resolved here. The answer (thanks to Meikel Brandmeyer on the Clojure mailing list) is to use
; 'type' as the dispatch function rather than 'class'.
(defmulti foo-print type)
(defmethod foo-print String [s] (println (format "String '%s'" s)))
(defmethod foo-print :default [thing] (println (format "don't know how to foo-print a %s" (class thing))))
(defmethod foo-print ::Foo [foo] (println (format "::FOO %s" (.toString foo))))
(compile 'play.foo)
(use 'play.foo)
(alias 'f 'play.foo)
(println "\nmake them...")
; x1, x2, and x5 will succeed with play.foo.Foo the result of (class)
; x3 and x4 will both be nil (with no exceptions)
(def x1 (play.foo/Foo 1))
(def x2 (Foo 2))
(def x3 (::f/Foo 3)) ;; nil
(def x4 (::f.Foo 4)) ;; nil
(def x5 (f/Foo 5))
(println (format "x1: %s" x1))
(println (format "x2: %s" x2))
(println (format "x3: %s" x3))
(println (format "x4: %s" x4))
(println (format "x5: %s" x5))
(println "\nfoo-print them...")
(foo-print x1)
(foo-print x2)
(foo-print x3)
(foo-print x4)
(foo-print x5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment