Ah, I see, thank you. Multimethods take a while getting used to I guess :) Definitely better for my problem than defprotocol though.
On 14/10/10 22:13, Armando Blancas wrote: > 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 - >
signature.asc
Description: OpenPGP digital signature