Maybe something like this. Those calls polymorphic on the returrn value of the anynimous function, so this is more powerful than overloading.
(defmulti load-page (fn [p n] (:id p))) (defmethod load-page :db [loader name] (println "db provider for page" name)) (defmethod load-page :fs [loader name] (println "fs provider for page" name)) (defmethod load-page :mock [loader name] (println "mock provider for page" name)) The loader data structure has a field that identifies which provider it has. The loader and providers may be records or maps: (defrecord prov-rec [f1 f2 f3]) (defrecord loader-rec [id prov]) ;; tests (def loader (loader-rec. :mock (prov-rec. nil nil nil))) (load-page loader "index.html") ;; real work (def loader (loader-rec. :db (prov-rec. "data" "user" "pwd"))) (load-page loader "index.html") Works with this one, too: (def loader { :id :fs :prov { :user "root" :pwd "***"} } ) On Oct 14, 3:08 am, "Felix H. Dahlke" <f...@ubercode.de> wrote: > Oh, I think I missed your suggestion of multimethods. They do in fact > look pretty interesting, but I wasn't able to figure out how that would > solve my problem - they look more like overloading than polymorphism to > me. Would you mind posting a variant of my example that uses multimethods? > > On 14/10/10 04:28, Armando Blancas wrote: > > > > > One thing that OOP and FP can have in common is the use of > > polymorphism. With protocols and types you can implement your Java > > design efficiently because you'll get basically the same interfaces > > and classes. The thing about hiding the calls to instances of a data > > type is only to make the client code not reply on the interop > > notation, even if it is only to call a method on them, just like > > Clojure core functions do. > > > With multimethods you can have different versions of the same > > function. You're right, you call it with the necessary data, one of > > which will be the one that controls the dispatch. Both data types and > > multimethods provide late-binding; the difference is that multi- > > methods are objects turned inside-out, as if you keep a reference to > > this (as a record with fields) and use in function calls. And each > > method is a particular responsibility. That's how I think about it, > > anyway. > > > Either choice should be fine. I write Java interfaces for > > implementations in Clojure when I want interop with Java, otherwise I > > use multimethods and do it all in Clojure. > > > On Oct 13, 1:37 pm, "Felix H. Dahlke" <f...@ubercode.de> wrote: > >> I see. So instead of using interfaces and implementations of these, I > >> would simply use closures, one for mock and one for production? That was > >> actually my first attempt, but I didn't like it back then. > > >> Take this code for example - passing a function just to have it called > >> feels weird: > > >> (defn load-page [provider name] > >> (provider name)) > > >> (load-page (make-mock-provider) "home") > > >> In Java, this would probably look like this: > > >> class PageLoader { > >> Provider provider; > > >> PageLoader(Provider p) { > >> provider = p; > >> } > > >> Page loadPage(String name) { > >> provider.loadPage(name); > >> } > > >> } > > >> PageLoader l = new PageLoader(new MockProvider()); > >> l.loadPage("home"); > > >> Then again, it might just feel weird because I've gotten very used to > >> OOP. In my Java code, loading pages is a responsibility of the > >> PageLoader and it delegates it to the Provider. Objects have > >> responsibilities and send messages to each other to fulfill these, > >> that's OOP. > > >> In functional programming, there's simply a function that has a certain > >> functionality, and everything it needs to fulfill it has to be provided > >> by the caller. That's at least how I understand it by now. > > >> Maybe I should just call the function returned by (make-mock-provider) > >> directly? The interface in Java has the great benefit of ensuring type > >> safety (plus there's no closures yet, so it's the only way), but does > >> this make sense in a dynamic language? I mean, if I passed an > >> implementation of the wrong interface or a closure with the wrong number > >> of arguments, wouldn't both situations result in weird runtime errors? > > >> On 12/10/10 22:34, Armando Blancas wrote: > > >>>> Back to my question: Am I trying to do Java in Clojure? Is there a more > >>>> Lisp-y way to do this? > > >>> You can hide the types so your client code is more lispy: > >>> (defn load-page [prov] (.loadPage prov)) > >>> ;;test > >>> (def mp (make-mock-provider)) ... (load-page mp) > >>> ;;production > >>> (def prov (make-provider)) ... (load-page prov) > > >>> Depending on your app the provider could be a singleton and need not > >>> be passed to each function. Another option is multimethods, in which > >>> case you'd be using mock functions with an argument that would > >>> indicate which version to dispatch to. > > >>> As for the repl, I think it works just as well for bottom-up and top- > >>> down development. I use it for both all the time and to avoid throw- > >>> away tests I write them top-down, black-box for only what's visible to > >>> client/interop code first, then move down the layers as the code is > >>> more mature and stable. I'm not really into TDD but I depend on a test > >>> suite as complete as I can get it. > > >> signature.asc > >> < 1KViewDownload > > > > signature.asc > < 1KViewDownload- Hide quoted text - > > - Show quoted text - -- 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