FWIW, also having struggled with overcoming circular ns deps in the past, I adopted the approach/compromise below which still provides an IMHO decent/sound usercode experience.
A contrived example: ;;;;;;;; core.clj (ns mylib.core (:require [mylib.types]) (:import [mylib.types Rect Circle])) (defprotocol IShape (bounds [this] "Returns shape's bounding rect") (bounding-circle [this] "Returns shape's bounding circle")) ;;;;;;;; types.clj (ns mylib.types) (defrecord Rect [x y w h]) (defrecord Circle [x y r]) ;;;;;;;; rect.clj (ns mylib.rect (:require [mylib.core :as c]) (:import [mylib.types Rect Circle])) (extend-type Rect c/IShape (bounds [this] this) (bounding-circle [{:keys [x y w h]}] (Circle. (+ x (/ w 2)) (+ y (/ h 2)) (/ (Math/sqrt (+ (* w w) (* h h))) 2)))) (defn make-rect "Factory fn with default values" [& {:keys [x y w h] :or {x 0 y 0 w 1 h 1}}] (Rect. x y w h)) ;(defn other-rect-specific-fn [] ...) ;;;;;;;; circle.clj (ns mylib.circle (:require [mylib.core :as c]) (:import [mylib.types Rect Circle])) ;(defn circle-specific-fn [x] ...) (extend-type Circle c/IShape (bounds [{:keys [x y r]}] (Rect. (- x r) (- y r) (* r 2) (* r 2))) (bounding-circle [this] this)) (defn make-circle "Factory fn with default values" [& {:keys [x y r] :or {x 0 y 0 r 1}}] (Circle. x y r)) etc. As a library user I then only need to require mylib.core and the namespaces of the types i want to work with. If my type namespaces provide additional type-specific fns (beyond the implementations of core protocols), then I know exactly where to find them... The other thing worth noting here is that this approach also provides a workaround for cases where there's a circular dependency between types as shown in the example above, i.e. getting the bounding circle of a rect & getting the bounding rect of a circle. This is achieved by the extra level of indirection via the mylib.types ns... In those cases one can't use the more handy factory fns of these types and has to resort to direct ctor calls, but this is only *inside* the library namespace and not in userland... I would be interested/keen to hear other opinions/approaches too. Thanks! On 12 December 2012 18:00, Michał Marczyk <michal.marc...@gmail.com> wrote: > @Jim: > > That function generates factory functions which themselves use no > reflection and incur no performance penalty at all. The only > performance hit visible at runtime comes from the fact that generating > those factory functions involves compiling code at runtime (but you > should hopefully be able to arrange things so that you only need to do > it once per type). > > Also, the class named by the recordname argument needs to exist when > record-factory is called, so I'm not sure it can really be of much > help in dealing with circular dependencies. > > Cheers, > Michał > > > On 12 December 2012 18:53, Jim - FooBar(); <jimpil1...@gmail.com> wrote: >> On 12/12/12 17:37, Mark Engelberg wrote: >> >> Yes and no. That's basically what I'm trying to do, but I only have a >> handful of concrete implementations to choose from, so I don't mind writing >> a hard-coded cond that chooses between them based on some sort of keyword >> that the user passes in. So the reflection aspect of this is not what >> interests me. >> >> >> aaa ok...I see. Well, your core ns certainly needs access to the >> implementation ns if you are going to use a plain cond. >> >> My problem is that I can't figure out how to put the implementations in >> different namespaces without introducing circular dependencies. The >> implementations need the core in order to implement the protocol. The core >> needs the implementation namespaces in order to provide a general >> constructor that can build all the concrete implementations. Does the use >> of reflection solve the circular dependency problem? I don't see how it >> would. >> >> >> Yes it would...You're using reflection so no need to :use or :require the >> namespaces any more. >> Point your browser here if you're not following: >> https://github.com/jimpil/Clondie24/blob/master/src/Clondie24/lib/util.clj >> >> this namespace depends on nothing (apart from clojure.pprint). However all >> the namespaces in games (the concrete implementations) depend on it. I can >> easily create a ChessPiece from within my chess ns using the record-factory >> in util.clj (even though util.clj knows nothing about games). However, as i >> said I'm not doing that...I'm advicing users to use the constructor (Foo.) >> or the factory fn (->Foo) cause they are massively faster...In my case it >> not that big of a deal cos the user is already is his namespace (in his >> game) so he does have access to everything he needs. I just wanted to >> streamline the process and essentially hide all the interop calls. No biggie >> for me... >> >> hope that helps... >> >> Jim >> >> -- >> 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 > > -- > 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 -- Karsten Schmidt +44 7875 524 336 http://postspectacular.com | http://toxiclibs.org | http://toxi.co.uk -- 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