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 -
> 


Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to