Dear Clojurians,

I picked up Clojure a few months ago and find it hugely fascinating.
I've been working mainly with Java for the past few years and now
trying to overcome the un-learning curve in regards to polymorphism
and solving it with records & protocols instead.

My aim is to port my library collection (http://toxiclibs.org) to
Clojure. The core libs contain several type hierarchies of geometric
entities (vectors, particles, shapes etc.) So I'm currently trying to
find the best solution to the following (but would just like to get my
head around this kind of problem in general):

In Java I've got a Vec2D class which has a large amount of methods
(80+) for vector algebra. I've also got a VerletParticle2D which
subclasses Vec2D, and adds a bunch of new properties (and methods). In
Java I only needed to implement the generic vector behaviours (adding,
normalizing, scaling etc.) once in the Vec2D class and they become
automatically available in VerletParticle2D. In Clojure I've tried to
achieve this with protocols, but I can't see a way how to provide the
same thing without having to re-implement the entire IVec2D protocol
for both record types. The following works of course, but IMHO
violates the DRY principle:

(defprotocol IVec2D
  (vadd [this v] "produces 2d vector sum of given vectors"))

(defrecord Vec2D [^double x ^double y]
  IVec2D
  (vadd [this v] (Vec2D. (+ x (:x v)) (+ y (:y v)))))

(defrecord VerletParticle2D
  [^double x ^double y ^double mass behaviors constraints]
  IVec2D
  (vadd [this v]
    (VerletParticle2D. (+ x (:x v)) (+ y (:y v)) mass behaviors
constraints)))

(def v (Vec2D. 23 42))
(def p (VerletParticle2D. 11 22 3 [] []))

(vadd v p) ; => #:user.Vec2D{:x 34.0, :y 64.0}
(vadd p v) ; => #:user.VerletParticle2D{:x 34.0, :y 64.0, :mass
3.0, :behaviors [], :constraints []}

The other option I thought of is using assoc instead of explicitly
creating new instances and then injecting these implementations via
the extend function:

(def IVec2D-impl {
  :vadd (fn [this v]
    (assoc this :x (+ (:x this) (:x v)) :y (+ (:y this) (:y v))))
})

(defrecord Vec2D [^double x ^double y])
(defrecord VerletParticle2D [^double x ^double y ^double mass
behaviors constraints])

(extend Vec2D IVec2D IVec2D-impl)
(extend VerletParticle2D IVec2D IVec2D-impl)

This is more concise, but also quite a lot slower due to assoc. Are
there any other options I can try to realise this? Also, in the latter
case, why does (parents Vec2D) doesn't list IVec2D, but in the former
it does? How can I express a VerletParticle2D is a Vec2D? Using derive
doesn't work with records...

Super grateful for any answers/pointers/solutions!

Thanks, K.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to