On Mon Mar 14 19:54 2011, stu wrote:
> The problem I have is with the myshapes.picture/draw function. As a
> Clojure newb I keep wanting to think of this like a polymorphic
> function in the O-O world that relies on each sequence member having a
> draw function.
> 
> What's the idiomatic way of handling a situation like this in
> Clojure?  Do I need to use richer data structures than vectors and
> structs for the shapes so they carry some kind of type information?  I
> can see how a draw multi-method would work if the individual shapes
> could be distinguished, or am I going about this the wrong way?

I believe there are two approaches to doing this in Clojure:

1. Multimethods: http://clojure.org/multimethods
2. Protocols: http://clojure.org/Protocols

Of the two, as of Clojure 1.2, protocols are the preferred way of doing
things.  They handle the simplest and most common case of polymorphism:
by type.

You can define a set of functions for your shapes:

(defprotocol Shape
  (draw [shape])
  (rotate [shape angle])
  …)

Then you can convert your structs into records.  So, instead of
something like:

(defstruct triangle :side1 :side2 :side3)

You now have:

(defrecord Triangle [side1 side2 side3])

You can implement your protocol inside of the defrecord itself or use
extend or extend-type.   An example of doing it inside of defrecord is:

(defrecord Triange [side1 side2 side3]
  Shape
  (draw [this]
    ; assumes sides satisfy Shape protocol
    (draw side1)
    (draw side2)
    (draw side3))

  (rotate [this]
    …)

  …)


This method works fairly well, and you can even use it to define
protocols for types you don't control, such as classes from a Java API.

If you need some more complicated form of dispatch for polymorphism,
there is the multimethod approach.

Sincerely,

Daniel Solano Gómez

Attachment: pgpSND14zVdtO.pgp
Description: PGP signature

Reply via email to