clojure-site
clojure-site copied to clipboard
Clarify how clojure.core/partial interacts with vars (and their values)
The way clojure.core/partial
captures the values of vars is not always apparent.
A typical scenario: A user wants to write a predicate function for checking whether an object implements a protocol. One obvious way is (def has-protocol? (partial satisfies? SomeProtocol))
. This may break unexpectedly if new implementations of the protocol are defined afterwards as the value of SomeProtocol
changes. CLJ-2094 exhibits this behaviour and offers a solution: use an anonymous function, #(satisfies? SomeProtocol %)
.
Perhaps this deserves an FAQ entry or a mention under the higher order functions article?
Personally, the way partial
works is not unexpected (even in this case), rather the way extending protocols work is what is surprising.
In most languages you don't really think about the nature of tokens that denote a class or interface. It's just syntax.
E.g. in java if you say x instanceof SomeInterface
you don't think about the nature of SomeInterface
syntax token. As far as programmer is concerned that is a type identifier, and it is stable and easy way to uniquely refer to a type.
A protocol reference is a var that is bound to immutable map value. At any time a namespace is loaded with some protocol extension, the var value is rebound to the new, updated map. These might be implementation details, but since they are not transparent to the user, the user needs to be aware of them. I've been using Clojure for years and I haven't realized that fact, and I'd bet there's many other people (and it's not exactly easy to debug this).
I think it would be appropriate to add warning to https://clojure.org/reference/protocols page:
Do not capture the value of protocol var (e.g. using "partial").
The protocol symbol points to a Var, which has a value of a protocol map. Every time a protocol implementation is added, the protocol Var is bound to a new protocol map value. Previously captured values do not have the additional implementation.
I think this makes most sense as a faq entry. Would also consider a link from the protocols page to the FAQ.