Using Clojure deftype as a parameterized function

I am trying to use clojure in the compiler and therefore I need to parameterize the calls on deftype ; however, I am having difficulty transferring hint types. Consider the following code:

 (defn describe [x] (let [fields (.getDeclaredFields x) names (map #(.getName %) fields) types (map #(.getType %) fields)] (interleave types names))) (defn direct [] (deftype direct-type [^int x])) (defn indirect-helper [] (list ^int (symbol "x"))) (defn indirect [] (eval `(deftype ~(symbol "indirect-type") ~(indirect-helper)))) 

And the following session from REPL:

 Clojure 1.2.0-master-SNAPSHOT 1:1 user=> #<Namespace dataclass> 1:2 dataclass=> (direct) dataclass.direct-type 1:3 dataclass=> (indirect) dataclass.indirect-type 1:4 dataclass=> (describe direct-type) (int "x") 1:5 dataclass=> (describe indirect-type) (java.lang.Object "x") 

Note that the generated class for an indirect type has lost ^ int hints that are of type direct. How do I get these tips?

+7
clojure
source share
1 answer

You need to modify indirect-helper to read

 (defn indirect-helper [] [(with-meta (symbol "x") {:tag 'int})]) 

The reason is that ^int parses as ^ followed by int ; ^ , in Clojure 1.2, introduces reader metadata (in 1.1 you would use #^ , which still works, but is deprecated in 1.2). Thus, ^int x in direct read as clojure.lang.Symbol , whose name is "x" and whose metadata display is {:tag int} (the int itself is a symbol here). (The final component of the character β€” its namespace β€” is nil in this case.)

In the indirect-helper version, ^int attached to (symbol "x") from the question text - a list containing the symbol symbol and the string "x" (which means, in particular, that (list ^int (symbol "x")) is evaluated as list of 1 item). This "hint type" is lost after evaluation (symbol "x") . To remedy the situation, you need a way to link metadata to the actual symbol generated (symbol "x") .

Now in this case, the symbol is generated at run time, so you cannot use read metadata to bind a type hint to it. Enter with-meta , which links metadata at run time (and is often useful when writing macros for the same reason as here), and the day is saved:

 user> (indirect) user.indirect-type user> (describe indirect-type) (int "x") 

(By the way, I thought deftype expecting a vector of field names, but apparently the list also works ... The vector is still more idiomatic.)

+7
source share

All Articles