Honza Pokorny
Honza Pokorny

Reputation: 3235

Provide multiple implementations for a Clojure protocol

I have a namespace that exposes common data-related functions (get-images, insert-user). I then have two database backends that have those same functions and implement them differently. They implement the interface as it were. Each backend is contained within a namespace.

I can't seem to be able to find a good solution on how to accomplish this.

I tried dynamically loading the ns but no luck. Once you do (:require [abc :as x]), the x isn't a real value.

I tried using defprotocol and deftype but that's all kinds of weird because the functions in the deftype need to be imported, too and that messes everything up for me.

Is there some idiomatic solution to this?

Upvotes: 4

Views: 456

Answers (1)

Alex Miller
Alex Miller

Reputation: 70211

I don't see why protocols are not sufficient?

In ns data.api:

(ns data.api)
(defprotocol DB
  (get-images [this]) 
  (insert-user [this]))

In ns data.impl1:

(ns data.impl1
  (:require [data.api :refer :all]))

(defrecord Database1 [connection-params]
  DB
  (get-images [_] ...)
  (insert-user [_] ...))

Same thing in ns data.impl2.

Then when you go to use a particular db, just create the correct record:

(ns data.user
  (:require [data.api :refer :all])
            [data.impl1 :refer (->Database1)])

(defn use-db []
  (let [db1 (->Database1 {})]
    (get-images db1)))

Upvotes: 9

Related Questions