Welcome! Please see the About page for a little more info on how this works.

+7 votes
in Clojure by

Because of implementation details of how def forms are compiled, invokations in its args are evaluated using applyTo rather than directly using the invoke method. This forces IFn implementors to implement applyTo even when not necessary.

The proposed patch changes InvokeExpr.eval to use AFn.applyToHelper, so that invoke rather than applyTo is used when possible.

Example of currently failing code that will work with patch:

user=> (deftype x [] clojure.lang.IFn (invoke [_] 1)) user.x user=> (def a ((x.))) AbstractMethodError clojure.lang.Compiler$InvokeExpr.eval (Compiler.java:3553)

I ran into this issue when using Pathom (https://github.com/wilkerlucio/pathom3). Pathom defines a `Resolver` defrecord. Resolvers implement IFn, and are generally intended to act like functions so they can be called directly e.g. for debugging purposes, though they are typically not expected to be called directly by the library user, but instead are called by the library during query running via the `.invoke` method.

I was trying to debug one of my resolvers and did something like `(def my-result (my-resolver my-args))` which threw the error described in this question. It took me a while digging through Clojure compiler code before suspecting that the fact I wrapped my function call in a `def` was the culprit.

Resolvers recently gained an implementation of `.applyTo` (https://github.com/wilkerlucio/pathom3/commit/0b40bc4aba7ff2d8e95dd4b120d04ef8d6c00cc7) so this problem no longer exists in Pathom, but I imagine it could easily be run into with older versions of Pathom or other libraries that define IFn implementations without realizing the need to implement `.applyTo`.

1 Answer

0 votes
Reference: https://clojure.atlassian.net/browse/CLJ-1715 (reported by bronsa)