Fork me on GitHub
#clojure-dev
<
2020-01-13
>
andy.fingerhut22:01:56

Am I correct in believing that derive , parents , and ancestors in clojure.core have no relationship with protocols?

andy.fingerhut22:01:53

And if the answer is "yes", is there anything built into Clojure that is like parents or ancestors that takes protocols into account? (Or if that would be ill-defined or not make sense for some reason, would appreciate some hints as to why)

bronsa22:01:25

no, protocols have no hierarchy semantics by design

andy.fingerhut22:01:10

Even if no hierarchy, something like "what protocols does this class/interface implement?" could be useful to query, perhaps?

bronsa22:01:48

but it's not possible to do, protocol implementations belong to the protocol not to the classes/interfaces

bronsa22:01:06

you'd have to scan the open universe of protocols to know which ones a class extends

andy.fingerhut22:01:28

In Clojure/Java, I have forgotten which ways of defining an implementation of a protocol do this, but some create a "class/interface extends Java-interface-of-protocol" relationship. Those can be seen via Java reflection API, and so also parents and ancestors . Double checking that to make sure I am not imagining things.

bronsa22:01:05

yes, that happens when you implement a protocol inline in a deftype

bronsa22:01:15

but it's merely an optimisation/implementation detail

bronsa22:01:33

and crucially it's not a thing that happens in all the ways a type can extend a protocol

andy.fingerhut22:01:11

Understood. I was a bit confused when I first came across that. It does mean some of those relationships show up in parents results, but not all, I think.

ghadi22:01:25

there is preference within protocols impls already: protocol extensions to concretions win over extensions to interfaces

bronsa22:01:55

are you talking about extend with meta?

bronsa22:01:19

oh nvm I understand what you mean

ghadi22:01:29

rephrased for broadcast: checking for a protocol implementation walks up the concrete hierarchy before the interfaces

andy.fingerhut22:01:46

I am still catching up, though 🙂 Ghadi, do you mean that if class A has an implementation for protocol P, and class A implements interface I1, and I1 has an implementation for protocol P, then calling a protocol P function on an instance of class A should always execute the class A implementation?

andy.fingerhut22:01:18

But still, if one was creating a "does X implement/extend Y" kind of diagram, "A implements P" is true in that situation, regardless of exactly which implementation of P is used.

ghadi22:01:22

right -- sorry I thought the original question was about preference when there is ambiguity

andy.fingerhut22:01:29

So there is no central "registry" of protocols in Clojure, but if you had a list of namespaces, you could walk through all of their Vars and look for them, based on knowing what protocols "look like" in the implementation details?

bronsa22:01:46

(note that in the case of multiple inheritance w/o a clear derivation preference, it's undefined which impl will be used)

bronsa22:01:11

@andy.fingerhut yes, but at a specific point in time

andy.fingerhut22:01:12

I don't mind the extra detail, but I was more asking whether there is already something like parents that, given A, would return P among the results, if A implements P

bronsa22:01:25

protocols can be extended a runtime

bronsa22:01:40

at t1 class A can not extend protocol P but at t2 it may

andy.fingerhut22:01:47

Well, Java classes can be loaded at runtime, too, so runtime changes don't bother me 🙂

ghadi22:01:15

I'm going to split hairs here @bronsa: the undefined impl case you're talking about is when you implement multiple interfaces to which the protocol is extended

1
andy.fingerhut22:01:23

Ah, I guess you mean that Java classes have their extends/implements-Java-interfaces relationships all known after the class is initialized, but protocols have another level of dynamicity beyond that?

andy.fingerhut22:01:13

Thanks for the clarification there. FYI, the reason for my asking is that I was hoping to enhance Stuart Sierra's class-diagram library to show "implements protocol" relationships, in addition to the parents / ancestors relationships that it shows now, and trying to figure out how.

bronsa22:01:34

i'm sure for tooling purposes it should be easy to get something working even tho it may not be correct/complete 100% of the cases

andy.fingerhut22:01:43

Among other enhancements that led me to look up 1970s CS algorithms papers on computing transitive reductions, which is something I've almost known how to do, but never in anger yet.

andy.fingerhut22:01:41

These diagrams can get visually messy pretty quickly.

andy.fingerhut22:01:37

No need for anyone to dig through lots of code, but as a semi-quick hack, looking through all Vars in a namespace for those whose value is a Clojure map, that contains at least the keys (:on :on-interface :sigs :var :method-map :method-builders) , seems likely to catch everything defined via Clojure/Java defprotocol , and while it could possibly catch other things, that seems somewhat unlikely to happen.

andy.fingerhut22:01:02

I could do additional sanity checks on the types/values associated with those keys, of course.

ghadi22:01:37

:impls too

ghadi22:01:50

if you don't see :impls that means the protocol has no extenders

andy.fingerhut22:01:11

I did a quick check, and :doc and :impls are not there when one first defines a protocol, but understood, yes.

andy.fingerhut22:01:28

And it does not gain a key :impls if one creates a deftype that implements the protocol.

ghadi23:01:18

yup, the extenders of an interface are an open set. (e.g. functions that return a reify)

andy.fingerhut23:01:01

Thanks for that info. For the purposes of this exercise I am going through, I am looking only for protocols that a given Java class/interface implements, not necessarily all Java objects that currently exist that implement them.