Thanks for your questions. I'll try to explain better. First, I'll explain that my line of work is to build tools to generate puzzles. I often have a module which generates the puzzles through various random processes, using certain probabilities and parameters. Then, I have another module that solves the puzzles. Another module analyzes the solving process to measure its difficulty. A final module filters and sorts the puzzles based on the analysis.
For an initial rapid prototyping programming session, it often suffices to just express each "module" as a separate file/namespace, with the key parameters as globals at the top of the file. These modules expressly refer to each other, with no indirection. But then, as I want to explore variations, it gets more complicated. What if I want to try a different set of parameters in the generator? What if I want to swap out the printing function in the analyzer? What if I want to swap out the whole analysis module with something different? For many years, my primary language for doing these sorts of programs has been Python. In my first pass, I just have a bunch of functions in a file with global variables at the top. For exploring simple changes, I can just import a file and then mutate the global parameters. When things get too complex for that, I reorganize into objects, and express the variation through inheritance and overriding the things I want to change. Right now, I'm working on my first sizeable project in Clojure. Again, I began by expressing each "module" as a file with some global parameters at the top. But now, I'm beginning to get to the point where I need to explore variations, and it's not clear to me how to reorganize. I don't want to post my actual code here, so let's run with this *gravity* example based off of what Adrian posted as a simple illustration. gravity.clj: (ns gravity) (def *gravity* 1.0) (defn say-grav [grav] (prn "Gravity is:" grav)) (defn halve-grav [] (/ *gravity* 2.0)) (defn mult-grav [x] (* *gravity* x)) (defn print-grav-stats [] (say-grav *gravity*) (say-grav (halve-grav)) (say-grav (mult-grav 2))) Now, let's say I want to explore the following: gravity_variation1.clj: (ns gravity-variation1) -- Copy of everything in gravity.clj except with the following changes -- (def *gravity* 0.38) (defn say-grav [grav] (prn "Gravity on Mars is:" grav)) And now I want to compare the two variations in one consumer file: consumer.clj: (ns consumer) (gravity/print-grav-stats) (gravity-variation1/print-grav-stats) So, how to do this in a clean way? And then, if I have other consumer files that use the gravity module, how do I set it up so that it is a parameter as to which gravity module they use? I've explored some of the dynamic rebinding techniques that Adrian suggested, but haven't been satisfied with the results. It's hard to constantly rebind things at the point of function call, and difficult to analyze what's going to happen as the code gets more complex, and you're using a mixture of functions from both "variations". I can start passing more and more things around as parameters, but that gets to be a rather complicated refactoring, and then these modules get much harder to use. So how to do this in other languages?: In Python, I might refactor as follows: class Gravity: gravity = 1.0 def halveGravity(self): return self.gravity/2.0 etc. One nuisance of refactoring a module written as globals-plus-functions into classes in Python is you have to explicitly insert self everywhere, but at least it's a very straightforward translation. In a language where the self reference is implied, it would be even easier (although most OO languages force you to use objects from the get-go, so there wouldn't really be any refactoring to do anyway). Then, you can express the variation through inheritance and overriding. The consumer code might look like: gravity = Gravity() gravityVariation1 = GravityVariation1() gravity.printGravStats() gravityVariation1.printGravStats() There are some tricks you can do to make these behave more like static methods, so they can be called without an instance, but that's not idiomatic Python. I haven't done a whole lot of Java, but I imagine that you could accomplish the same thing by using a class with static methods to represent a "module" of code. I've recently been reading the Scala book, and it seems like they've taken the idea of singleton objects as modules one step further, along with traits to handle mixins of partial implementations, in order to address a lot of these issues even better than vanilla Java. And what about functional languages? Well, I'm pretty sure that PLT Scheme has a sophisticated modular mechanism called Units which handle these sorts of issues. And I think that ML can parameterize modules in the form of functors (or is that only a parameterization over types?). So please, I'd love to hear more ideas about how to write my Clojure code in a more modular way, making it easier to explore and maintain variations, and dynamically link the sets of modules I want to use to solve a given problem. Thanks! --~--~---------~--~----~------------~-------~--~----~ 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 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 -~----------~----~----~----~------~----~------~--~---