The most straightforward one: just make your protocols a thing that your 
storage medium implements, instead of your records.  E.g.:

(defprotocol ThingStore
  (load-item [store item-id])
  (load-items [store item-ids])
  (find-item [store item-name])
  (save-item [store item]))

(defrecord DatabaseStore
  ThingStore
  (load-item [store item-id] ...))

Otherwise, Clojure does have multimethods, but the dispatch mechanism 
doesn't work the same was as Common Lisp's.  You could probably combine 
multimethods with a marker protocol to do what you're trying.

;; First, an empty marker protocol
(defprotocol Loadable)

;; And something that you want to load
(defrecord Thing [data]
  Loadable ;; mark that it implements that empty protocol
)

;; Define a multimethod dispatch function that will figure out the right 
implementation to call
(defn loadable-dispatch
  [item]
  (cond (satisfies? Loadable item) ::load-one-item
       (and (sequential? item) (every? #(satisfies? Loadable %) item)) 
::load-many-items
       :else nil))

;; The multimethod itself
(defmulti load-item loadable-dispatch)

;; And implementations
(defmethod load-item ::load-one-item
  [item]
  "Load one item.")

(defmethod load-item ::load-many-items
  [items]
  "Load many items.")

user> (load-item (map->Thing {}))
"Load one item."

user> (load-item [(map->Thing {}) (map->Thing {})])
"Load many items."

Overall, you're probably better off with the first option, but you can make 
multimethods work for you here if you want.

On Sunday, August 28, 2016 at 7:29:46 AM UTC-7, Jonathon McKitrick wrote:
>
> I'm beginning a foray into protocols after coming from the Common Lisp 
> world of multimethods. I'm using them initially to implement a consistent 
> load/save API over the DB layer.
>
> It's pretty simple to have a Saveable protocol to save one object, because 
> the first argument is a Record of the type I am saving.
>
> But since protocols dispatch on the first argument, how do you define a 
> Loadable protocol that loads an object or handles a collection of objects?
>
> For example, if I want to load an object by idx, the first argument is not 
> a Record, but an integer, or perhaps an arbitrary field to used in a query.
>
>
>

-- 
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 unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to