Reputation: 9985
Is there a documented way to find which protocols are implemented by a Clojure object? The other way around (show for which classes a given protocol is extended) is easy: (extenders protocol).
Upvotes: 10
Views: 3127
Reputation: 5759
Old question, and there is an accepted answer... however I would perhaps do something like this:
(defprotocol FooP
(foo [this]))
(defrecord Foo []
FooP
(foo [this] :whatever))
if you know the protocol that you want to check, then you can use satisfies?
> (satisfies? FooP (->Foo))
true
If not, then you could at least find all interfaces using the following
(defn interfaces [o]
(for [interface (.getInterfaces (class o))]
(.getCanonicalName ^Class interface)))
which you can check
> (interfaces (->Foo))
("com.beoliver.FooP" "clojure.lang.IRecord" "clojure.lang.IHashEq" "clojure.lang.IObj" "clojure.lang.ILookup" "clojure.lang.IKeywordLookup" "clojure.lang.IPersistentMap" "java.util.Map" "java.io.Serializable")
> (interfaces [])
("clojure.lang.IObj" "clojure.lang.IEditableCollection" "clojure.lang.IReduce" "clojure.lang.IKVReduce")
> (interfaces {})
("clojure.lang.IObj" "clojure.lang.IEditableCollection" "clojure.lang.IMapIterable" "clojure.lang.IKVReduce")
If you map bean
over the interfaces insead of calling .getCanonicalName
you will be able to see all of the options.
Upvotes: 0
Reputation: 9985
I ended up with the following implementation:
(defn protocol? [maybe-p]
(boolean (:on-interface maybe-p)))
(defn all-protocols []
(filter #(protocol? @(val %)) (ns-publics *ns*)))
(defn implemented-protocols [sym]
(filter #(satisfies? @(val %) sym) (all-protocols)))
First it looks for all the symbols in the current namespace (you can of course extend this to all namespaces) whether they are protocol definitions or net (all-protocols). Next it looks for a given symbol if it satisfies one of these protocols.
The protocol? function uses the :on-interface key which isn't documented afaik, so this function is not portable.
Upvotes: 6
Reputation: 336
I can't actually try this at the moment, but you might want to try the Java class method: getGenericInterfaces
. This should give you a list of interfaces. There are probably other ways to get this information using similar methods but I haven't looked.
If you also look at the source code you'll see how protocols are set up (you can get to the source by clicking on the links in the clojure api). In Clojure 1.3 there is a 'private' function that looks like this:
(defn- protocol?
[maybe-p]
(boolean (:on-interface maybe-p)))
This function is used by Clojure's extend
function to check that you've actually provided a Protocol. If you make your own function like that you can filter the results of getGenericInterfaces
. Since this is an internal detail it might be subject to change.
Upvotes: 0