I agree that deftype (or perhaps defrecord ) is better than proxy to do this in Clojure, but at the end of my comments we’ll cover all the possibilities.
For your question after UPDATE 2.
You can add “properties” to entries by specifying them in an arglist:
(deftype Particle [position radius prop3 prop4] ... )
Remember that types in Clojure are immutable, so after creating an object there is no concept of setting properties. If some of the properties are optional, it is recommended that you use the best factory methods, for example:
(defn make-particle ([position] (Particle. position nil nil nil)) ([position radius] (Particle. position radius nil nil)) ;; etc. add more here as needed )
You might want to consider completely removing types and simply using maps that have any “properties / fields” inside them that you need. Types are useful when you need to implement abstractions. For your ParticleProtocol - what is the value it provides? Protocols are designed to provide polymorphism, so you will have several implementations of this protocol?
Chas Emerick completed a detailed description of how to choose a data type in Clojure that can help you: http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form / p>
[Update showing an example implementation of a map] :
To create a map with a “property” and get this property, you would do:
(def mymap {:myfloat 3.1415926}) (println "myfloat has value:" (:myfloat mymap))
To provide additional functions, such as a "rendering" function, simply create fn, which accepts a map with the necessary keys:
;; the details are bogus, just showing the syntax (defn render [m] (no-stroke) (fill (:radius m) (:position m)) (do-something-else (:position m)))
For your update , if you want to update the values in the particle map, you need to create a new map, not update the existing one.
(def myparticle {:position 100 :radius 25}) (defn change-pos [particle-map new-pos] (assoc-in particle-map [:position] new-pos)) (let [new-particle (change-pos myparticle 300)] (println new-particle)) ;; prints out {:position 300 :radius 25} ;; orig myparticle still has value {:position 100 :radius 25} ;; or do it directly (println (assoc myparticle :position 300)) ;; prints out {:position 300 :radius 25}