The protocol interlock for a scoped reload, read off the LIVE image.
Reloading a namespace that defines a protocol (defprotocol) or an interface (definterface) replaces the protocol object / interface class. Every implementation built against the OLD one is orphaned: a defrecord compiled against the old interface no longer implements the new one, and the protocol's fresh :impls map has forgotten every extend. The symptom reads as a defect in the implementor - "No implementation of method: :m of protocol #'p/P found for class: x.Rec" - for a class that plainly implements it.
clj-reload already reloads the require-graph dependents of a changed namespace, but only the ones in loaded-libs, and only the ones the require graph can see. An implementor that extends a protocol it reached through requiring-resolve, a live namespace an earlier failed pass dropped from loaded-libs, or a dependent a failed pass left unloaded all escape it. This namespace names, BEFORE a pass, every namespace that has to be reloaded after each protocol definer the pass would reload, so the pass can be checked - and completed - against that list afterwards.
It also decides which definers must NOT be reloaded in place: one outside the roots being reloaded (a co-tenant's or a pinned SPI port, which this reload has no business replacing), and one whose implementors include a namespace clj-reload does not track (a jar, a REPL-made namespace): those could never be reloaded, so replacing the protocol would orphan them for good. Such a definer is PINNED for the pass and reported.
Pure reads of the image: no var is dereferenced except a protocol var, whose value is the protocol map itself.
The protocol interlock for a scoped reload, read off the LIVE image. Reloading a namespace that defines a protocol (defprotocol) or an interface (definterface) replaces the protocol object / interface class. Every implementation built against the OLD one is orphaned: a defrecord compiled against the old interface no longer implements the new one, and the protocol's fresh :impls map has forgotten every extend. The symptom reads as a defect in the implementor - "No implementation of method: :m of protocol #'p/P found for class: x.Rec" - for a class that plainly implements it. clj-reload already reloads the require-graph dependents of a changed namespace, but only the ones in *loaded-libs*, and only the ones the require graph can see. An implementor that extends a protocol it reached through requiring-resolve, a live namespace an earlier failed pass dropped from *loaded-libs*, or a dependent a failed pass left unloaded all escape it. This namespace names, BEFORE a pass, every namespace that has to be reloaded after each protocol definer the pass would reload, so the pass can be checked - and completed - against that list afterwards. It also decides which definers must NOT be reloaded in place: one outside the roots being reloaded (a co-tenant's or a pinned SPI port, which this reload has no business replacing), and one whose implementors include a namespace clj-reload does not track (a jar, a REPL-made namespace): those could never be reloaded, so replacing the protocol would orphan them for good. Such a definer is PINNED for the pass and reported. Pure reads of the image: no var is dereferenced except a protocol var, whose value is the protocol map itself.
(analyze
{:keys [candidates deps tracked? in-roots? no-reload]
:or {tracked? (constantly true) in-roots? (constantly true) no-reload #{}}})The protocol interlock for one pass.
candidates are the namespaces the pass may reload (its cascade). Each LIVE
one that defines a protocol or interface is a definer, with the namespaces
that must be reloaded after it: its implementors (see implementors) plus
its live direct require-graph dependents (deps, clj-reload's dependees
map {ns #{dependent}}), whose compiled call sites hold the old method vars.
A definer is PINNED, with a reason, when
:no-reload the host already pins it (config :no-reload)
:outside-roots in-roots? says it lives outside the reloaded roots
:untracked-implementors an implementor is not tracked?, so could never be
reloaded after it
Returns {:definers {ns #{must-follow ...}} - definers the pass reloads :pinned {ns {:reason kw :implementors [ns ...]}}}
The protocol interlock for one pass.
`candidates` are the namespaces the pass may reload (its cascade). Each LIVE
one that defines a protocol or interface is a definer, with the namespaces
that must be reloaded after it: its implementors (see `implementors`) plus
its live direct require-graph dependents (`deps`, clj-reload's dependees
map {ns #{dependent}}), whose compiled call sites hold the old method vars.
A definer is PINNED, with a reason, when
:no-reload the host already pins it (config :no-reload)
:outside-roots `in-roots?` says it lives outside the reloaded roots
:untracked-implementors an implementor is not `tracked?`, so could never be
reloaded after it
Returns {:definers {ns #{must-follow ...}} - definers the pass reloads
:pinned {ns {:reason kw :implementors [ns ...]}}}(defines-protocol? ns-sym)Does the loaded namespace ns-sym define a protocol or an interface?
Does the loaded namespace `ns-sym` define a protocol or an interface?
(implementors ns-sym)Live namespaces, other than ns-sym, holding an implementation of a
protocol or interface ns-sym defines:
inline - a class the namespace defined (defrecord / deftype) that implements one of the interfaces extended - the namespace whose fns sit in a protocol's :impls (extend, extend-type, extend-protocol)
Namespaces under clojure.* are never counted.
Live namespaces, other than `ns-sym`, holding an implementation of a
protocol or interface `ns-sym` defines:
inline - a class the namespace defined (defrecord / deftype) that
implements one of the interfaces
extended - the namespace whose fns sit in a protocol's :impls
(extend, extend-type, extend-protocol)
Namespaces under clojure.* are never counted.(interfaces ns-sym)The interfaces ns-sym defined and imported (definterface / gen-interface),
plus the backing interface of every protocol it defines.
The interfaces `ns-sym` defined and imported (definterface / gen-interface), plus the backing interface of every protocol it defines.
(pinned-report pinned)Wire-safe projection of the pinned definers.
Wire-safe projection of the pinned definers.
(protocols ns-sym)The protocol maps ns-sym defines, found through the :protocol metadata
defprotocol stamps on each method var it interns. Empty when the namespace
is not loaded.
The protocol maps `ns-sym` defines, found through the `:protocol` metadata defprotocol stamps on each method var it interns. Empty when the namespace is not loaded.
(stale-followers definers loaded)Given the definers an analyze call returned and the ordered loaded
namespaces of a pass, every namespace that had to be reloaded AFTER a
definer the pass loaded, but was not: never loaded, or loaded before it.
Answers {definer #{ns ...}} with empty entries dropped.
Given the definers an `analyze` call returned and the ordered `loaded`
namespaces of a pass, every namespace that had to be reloaded AFTER a
definer the pass loaded, but was not: never loaded, or loaded before it.
Answers {definer #{ns ...}} with empty entries dropped.cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |