Attached is a patch that adds doc-string and metadata support to
defmulti. It does not generate arglists metadata automatically like
defn does since the arglists are not supplied in the defmulti form as
they are in defn. One possibility would be to see if the dispatch
function has an :arglists entry in its metadata and use that if it
does, but I did not include that here since it opens up the
possibility that the :arglists and :doc entries could get out of sync.
Below is a sample usage of the new doc-string support. I'd be
interested to hear people's thoughts.
Regards,
- J.
kant[~/src/clojure]$ iclj
1:1 user=> (defmulti fib "Calculates the nth value of the fib sequence"
{:arglists '([n])}
int)
#'user/fib
1:3 user=> (defmethod fib 0 [_] 0)
#<MultiFn clojure.lang.MultiFn@acb158>
1:4 user=> (defmethod fib 1 [_] 1)
#<MultiFn clojure.lang.MultiFn@acb158>
1:5 user=> (defmethod fib :default [n] (+ (fib (- n 2)) (fib (- n 1))))
#<MultiFn clojure.lang.MultiFn@acb158>
1:6 user=> (map fib (range 10))
(0 1 1 2 3 5 8 13 21 34)
1:7 user=> (doc fib)
-------------------------
user/fib
([n])
Calculates the nth value of the fib sequence
nil
1:8 user=> (meta (var fib))
{:line 1, :file "repl-1", :doc "Calculates the nth value of the fib
sequence", :arglists ([n]), :tag clojure.lang.MultiFn, :name fib, :ns
#<Namespace user>}
This is a breaking change for some (granted rather unsual) cases:
(defmulti foo {:a 1 :b 2})
(defmethod foo 1 [_] "got a1")
(defmethod foo 2 [_] "got b2")
Before patch:
user=> (foo :a)
"got a1"
user=> (foo :b)
"got b2"
After patch:
user=> (foo :a)
java.lang.NullPointerException (NO_SOURCE_FILE:0)
user=> (foo :b)
java.lang.NullPointerException (NO_SOURCE_FILE:0)
You can see what happened to our dispatch map:
user=> ^#'foo
{:tag clojure.lang.MultiFn, :name foo, :file "NO_SOURCE_FILE", :ns
#<Namespace user>, :line 1, :b 2, :a 1}
I'm not offering an opinion here on whether or not it's a good patch,
just wanted to point out it changes currently defined behavior.
--Chouser
Or, worse yet:
(defmulti foo {:a {:b "B"}} {:c "C"})
Which would become ambiguous after this patch. Good catch, Chouser.
> I'm not offering an opinion here on whether or not it's a good patch,
> just wanted to point out it changes currently defined behavior.
Thanks for pointing that out. I did this mostly as a learning
experience, because it seemed like something that would be useful.
However, it's not something I have a need for at the moment, so I've
mostly gotten out of it what I was looking for :)
Before giving up on it, one approach that might work for now would be
to allow a doc-string, but not the attr-map. Since a string isn't a
valid parameter for the dispatch function, there would be no
possibility for ambiguity and I believe it is completely backwards
compatible. I've attached a patch that implements this. Sample usage:
1:7 user=> (defmulti #^{:arglists '([n])} fib "docs for fib" int)
#'user/fib
1:8 user=> (doc fib)
-------------------------
user/fib
([n])
docs for fib
nil
Thoughts welcome. I'll be happy to implement any suggested changes.
If, on the other hand, there is no further interest in this, I'll let
it go since I don't have a need for it at the moment, anyhow. However,
it does seem like it would be nice if defmulti had similar doc support
to defn and defmacro.
Regards,
- J.