clojure-site icon indicating copy to clipboard operation
clojure-site copied to clipboard

Clarify how clojure.core/partial interacts with vars (and their values)

Open lassemaatta opened this issue 3 years ago • 2 comments

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?

lassemaatta avatar Jul 28 '21 17:07 lassemaatta

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.

RokLenarcic avatar Jul 28 '21 18:07 RokLenarcic

I think this makes most sense as a faq entry. Would also consider a link from the protocols page to the FAQ.

puredanger avatar Aug 17 '21 12:08 puredanger