Why can't I bind defrecord in clojure?

I have something like this:

user> (defrecord vertex [id val]) => user.vertex
user> (def v vertex)              => #'user/v
user> (= v vertex)                => true
user> (type v)                    => java.lang.Class
user> (type vertex)               => java.lang.Class
user> (vertex. 1 2)               => #user.vertex{:id 1, :val 2}
user> (v. 1 2)                    => "Unable to resolve classname v"
user> (new v 1 2)                 => "Unable to resolve classname v"

      

So basically I cannot bind a vertex to a different name. It's the same with trying to pass the defrecord type to a function, or let, or whatever. Why is this, and what can I do to temporarily rename the defrecord?

I guess this is a Java interop related trick.

+3


source to share


2 answers


defrecord

generates a Java class, which in my opinion is actually viewed as a form of special case in Clojure, specifically with regard to interoperability (although I'm not sure).

If your goal is to be able to easily bypass a function that can create vertices, then the solution is to use a local function that calls the constructor rather than doing the interop itself.

In Clojure 1.3, deftype and defrecord automatically generate two additional methods:



  • ->{type}

    equivalent to constructor
  • map->{type}

    takes a map of arguments as an argument

For the above, (->vertex 1 2)

both (map->vertex {:id 1 :val 2})

work and allow you to complete the construct you are doing.

If you really want a class that is accessible as you go through it, there might be something you can do with macros, although I'm not sure.

+4


source


This is not possible as far as I know.

If you are thinking about how defrecord works; The bytecode actually generates the (java) class. You can see this in action when you do defrecord in one namespace and want to use it in another ...



(ns my-first-namespace)
(defrecord Foo [x y])

(ns my-second-namespace
   (:use my-first-namespace)
   (:import my_first_namespace Foo)) ; still have to import the java class 
                                     ; underlying the defrecord even tho 
                                     ; the defining namespace is use'd (note 
                                     ; hyphen / underscore changes). 

      

Unfortunately, in java (really in the JVM) there is no way to list a class name to another class. The closest you can get is subclassing to the new name, but that's pretty crude.

+2


source







All Articles