Vararg in protocol methods

1,406 views
Skip to first unread message

dennis

unread,
Jan 19, 2011, 11:02:48 PM1/19/11
to Clojure
I have defined a protocol with overload methods,and one has varargs:

(ns test)
(defprotocol Say
(say [this a] [this a & b] "say hello"))
(defrecord Robot []
Say
(say [this a] (println (str "hello," a)))
(say [this a & b] (println b)))

Then ,i new a robot and say something:
(let [ r (Robot.)]
(say r "dennis"))

It worked and print "hello,dennis",but if i passed more than one
arguments,it failed:

(let [ r (Robot.)]
(say r "dennis" "zhuang"))

and threw exception

java.lang.IllegalArgumentException: No single method: say of
interface: test.Say found for function: say of protocol: Say (test.clj:
9)

It seems that clojure find methods in protocol both by name and
arity,and in this situation it found more than one methods named
"say".

I don't know how to solve this problem,any suggestion? thanks a lot.

Alan

unread,
Jan 20, 2011, 2:09:44 AM1/20/11
to Clojure
Protocols don't support varargs. You've defined a protocol with two
methods named say: one takes one argument named a, the other takes
three arguments named a, &, and b.

Protocols are for describing a very minimal set of functionality
needed to implement some richer feature set; the idea is that you
define a Say protocol that is capable of saying things in some basic
sense, and then build a library of functions that operate on Sayable
objects, providing the nice syntactical sugar in the library of real
functions, not in the protocol itself. If you want a say function that
behaves totally differently depending on how many arguments it's
passed (which seems kinda silly, but I'll assume that it's a contrived
example), you could do something more like this:

(defprotocol Say
(say [this args]))

(defrecord Robot []
Say
(say [this args]
(let [[a & [b]] args]
(println (or b (str "hello, " a))))))

(defn make-something-talk [obj & args]
(say obj args))
Reply all
Reply to author
Forward
0 new messages