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

+1 vote
in Clojure by

Hello! I'm not sure if this is a bug, so I'll report here and ask, "is this expected?"

It seems that defrecord and deftype forms don't have access to bindings in their lexical closure. Both of the following type declarations fail in Clojure 1.10.1 with " Unable to resolve symbol: x in this context":

(defprotocol ID
  (id [x] x))

(let [x 10]
  (deftype TType []
    ID
    (id [_] x)))

(let [x 10]
  (defrecord TRecord []
    ID
    (id [_] x)))

Cheers!

1 Answer

0 votes
by
selected by
 
Best answer

This is expected, and not a bug - this is doc'ed in the deftype docstring.

by
I see it now! Thank you, and here's the relevant comment for anyone that sees this down the road:

Note that method bodies are not closures, the local environment includes only the named fields, and those fields can be accessed directly."
by
However


    (defprotocol ID
        (id [x] x))
    
      (let [x 42
            f (fn [_] x)]
        (extend
         java.util.Properties
          ID
          {:id f}))

      (id (java.util.Properties.))
      ;; => 42
by
The question was about deftype/defrecord methods, so not sure why this is relevant.
by
Methods attached via "extend" close over their environment. Thus, you can choose whether to declare protocol implementation lexically inside deftype (in which case the type's members are in the methods' environment) or with extend (in which case members are accessible only via the 'this' parameter, but the functions enjoy whatever environment they closed over).
Welcome to Clojure Q&A, where you can ask questions and receive answers from members of the Clojure community.
...