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