Nested Multimethods

105 views
Skip to first unread message

CuppoJava

unread,
Oct 13, 2008, 11:01:19 PM10/13/08
to Clojure
Is there anyway to do the following with the existing multi-method
facilities?

There is a general multi-method length(object) that splits off to
different methods depending on the :class of the object.

And then specifically for objects with :class = :stateMachine, I want
to define it's method to split off further depending on the :state of
the object.

(defmulti length :class)
(defmethod-multi length :stateMachine :state)

(defmethod length :stateMachine :walking
(println "Short distance"))

(defmethod length :stateMachine :running
(println "Long distance"))

Thanks very much for your help.
-Patrick

Stuart Halloway

unread,
Oct 13, 2008, 11:14:44 PM10/13/08
to clo...@googlegroups.com
Hi Patrick,

How about:

(defmulti length (fn [x]
(if (= :stateMachine (:class x))
(:state x)
(:class x))))

(defmethod length :yardstick [x] 36)
(defmethod length :walking [x] "short")
(defmethod length :running [x] "long")

user=> (length {:class :yardstick})
36
user=> (length {:class :stateMachine :state :walking})
"short"
user=> (length {:class :stateMachine :state :running})
"long"

It would probably be better to have the fn return a vector so you
don't have to worry about :state and :class values with colliding
names, but that's the basic idea.

Cheers,
Stuart

Rich Hickey

unread,
Oct 14, 2008, 8:30:11 AM10/14/08
to Clojure
The answer is right in your title - use more than one multimethod and
nest them:

(defmulti length :class)
(defmulti sm-length :state)

(defmethod length :stateMachine [x]
(sm-length x))

(defmethod sm-length :walking [_]
(println "Short distance"))

(defmethod sm-length :running [_]
(println "Long distance"))

(length {:class :stateMachine :state :running})
-> Long distance

Rich

Rich Hickey

unread,
Oct 14, 2008, 8:54:14 AM10/14/08
to clo...@googlegroups.com
On Mon, Oct 13, 2008 at 11:14 PM, Stuart Halloway
<stuart....@gmail.com> wrote:
>
> Hi Patrick,
>
> How about:
>
> (defmulti length (fn [x]
> (if (= :stateMachine (:class x))
> (:state x)
> (:class x))))
>
> (defmethod length :yardstick [x] 36)
> (defmethod length :walking [x] "short")
> (defmethod length :running [x] "long")
>
> user=> (length {:class :yardstick})
> 36
> user=> (length {:class :stateMachine :state :walking})
> "short"
> user=> (length {:class :stateMachine :state :running})
> "long"
>
> It would probably be better to have the fn return a vector so you
> don't have to worry about :state and :class values with colliding
> names, but that's the basic idea.
>

In general, if you have a conditional or other enumeration of things
in your dispatch method it is a warning sign that you might not be
getting the leverage out of multimethods - their prime reason to exist
is to provide open, extensible case logic.

Never say never, but in this case it's better to use two multimethods.

Rich

CuppoJava

unread,
Oct 14, 2008, 10:48:43 AM10/14/08
to Clojure
That's a very elegant solution Rich. I'm so obvious when someone tells
you how to do it.

Clojure amazes me more every day. All the painfully accumulated
knowledge of Java design patterns are so trivial in Clojure. It
doesn't even seem like there's any need for design "patterns" at all
anymore cause everything is handled elegantly by the base language.

Randall R Schulz

unread,
Oct 14, 2008, 10:58:38 AM10/14/08
to clo...@googlegroups.com

I have heard it claimed (on one of the Scala lists, I think) that
patterns themselves are an anti-pattern...


Randall Schulz

mb

unread,
Oct 14, 2008, 11:24:40 AM10/14/08
to Clojure
Hello,

On 14 Okt., 16:58, Randall R Schulz <rsch...@sonic.net> wrote:
> I have heard it claimed (on one of the Scala lists, I think)
> that patterns themselves are an anti-pattern...

I think there are always patterns. They are just different. In
Clojure there is maybe the "Driver Function" pattern: Instead
of writing a huge macro, put the logic in a driver function,
package up the arguments in (fn [] ...) closures and pass
them to the driver.

Sincerely
Meikel

Reply all
Reply to author
Forward
0 new messages