Clojure: how to create a record inside a function? - clojure

In clojure, I would like to create a record inside a function.
I tried:
(defn foo []
(defrecord MyRecord [a b])
(let [b (MyRecord. "1" "2")]))
But it causes an exception:
java.lang.IllegalArgumentException: Unable to resolve classname: MyRecord
Any idea?

The key points
You should only use defrecord at top level.1
So, if you do need a custom record type, you should define it outside of foo (at some point in your code which gets processed before foo's definition).
Otherwise, you could just use a regular map. In particular, if foo will be creating entities of multiple "types" (at the conceptual level), it probably makes no sense to try to create a record type (a Java class) for each; the natural solution would be to use maps holding a :type key to indicate the sort of entity represented.
Why it doesn't work
The code from the question doesn't compile, because Clojure's compiler resolves class names mentioned as first arguments to new forms at compile time. ((MyRecord. "1" "2") is expanded to (new MyRecord "1" "2") during the macro expansion process.) Here the name MyRecord cannot yet be resolved to the appropriate class, because the latter has not yet been defined (it would be created by the defrecord form after foo was first called).
To get around this, you could do something horrible like
(defn foo []
(eval '(defrecord MyRecord [x y]))
(let [b (clojure.lang.Reflector/invokeConstructor
;; assuming MyRecord will get created in the user ns:
(Class/forName "user.MyRecord")
(into-array Object ["1" "2"]))]
b))
which causes a kitten to have its finalize method invoked through reflection, resulting in a gruesome death.
As a final remark, the above horrible version would sort of work, but it would also create a new record type under the same name at each invocation. This causes weirdness to ensue. Try the following examples for a flavour:
(defprotocol PFoo (-foo [this]))
(defrecord Foo [x]
PFoo
(-foo [this] :foo))
(def f1 (Foo. 1))
(defrecord Foo [x])
(extend-protocol PFoo
Foo
(-foo [this] :bar))
(def f2 (Foo. 2))
(defrecord Foo [x])
(def f3 (Foo. 3))
(-foo f1)
; => :foo
(-foo f2)
; => :bar
(-foo f3)
; breaks
;; and of course
(identical? (class f1) (class f2))
; => false
(instance? (class f1) f2)
; => false
At this point, (Class/forName "user.Foo") (assuming again that all this happens in the user namespace) returns the class of f3, of which neither f1 nor f2 is an instance.
1 Macros occasionally might output a defrecord form wrapped in a do along with some other forms; top-level dos are special, though, in that they act as if the forms they wrap were individually processed at top level.

Related

def and resolve in the same clojure macro

I want to achieve to return a namespace resolved symbol in a macro that has recently defined the symbol itself:
(ns my-namespace)
(defmacro def&resolve [a b]
`(do
(def ~a 12)
(def ~b ~(resolve a))))
(def&resolve foo bar)
bar ;=> nil
In the example bar returns nil. I however, want it to return my-namespace.foo. I know this is not working since at the time resolve is called, a isn't defined yet. I need a to be namespace-resolved at macro-expansion time for my use case [1], however.
In the next run I wanted to declare a at macro expansion time (does that even make sense?) and, thus, force that it is present in the current ns when calling resolve.
(defmacro def&resolve [a b]
(declare a)
`(do (def ~a 12)
(def ~b ~(resolve a))))
(def&resolve foo bar)
bar ;=> nil
Doesn't work either.
How can I def something and at the very macro expansion namespace resolve it?
[1] My use case is the following: I want to define a bundle of functions and add it to the meta information of a def-binding (thus, I need it at macro expansion time). Currently, I only store the symbols, without the namespace the functions were defined in.
(ns another-namespace)
(defmacro def&resolve [a b]
`(do
(def ~a 12)
(def ~b (resolve '~a))))
(macroexpand-1 '(def&resolve foo bar))
#=> (do (def foo 12) (def bar (clojure.core/resolve (quote foo))))
(def&resolve foo bar)
bar
#=> #'another-namespace/foo
since the var will be def'ed/created at run time, once the macro has finished it's job and gone away, the macro can instead predict what the var will be named and create the symbol directly rather than making a round trip through the namespace and back
Let's do it manually first
user> (def foo)
#'user/foo
user> (resolve 'foo)
#'user/foo
that looks right, now let's do it by creating the symbol:
user> (symbol (str *ns* "/" "foo"))
user/foo
and copy that into the macro definition:
user> (defmacro def&resolve [a b]
`(do
(def ~a 12)
(def ~b ~(symbol (str *ns* "/" "foo")))))
#'user/def&resolve
and test it out
user> (def&resolve foo bar)
#'user/bar
user> bar
12
This method is preferable to the approach of using intern to create the symbol in the namespace using a dummy value, at macro expand time, then resolveing it also at macro expansion time. Resulting in the same value. The advantage of this approach is that it does make resolve work at macro expand time as in your original question
user> (do (intern *ns* 'a :dummy-value)
(resolve 'a))
#'user/a
though i recommend going with the symbol generation approach.
Nesting of syntax quote helps, with additional quoting of ~a:
(defmacro def&resolve
[a b]
`(do
(def ~a 12)
(def ~b ~`(resolve '~a))))
#'test-project.core/def&resolve
test-project.core=> (macroexpand '(def&resolve foo bar))
(do (def foo 12) (def bar (clojure.core/resolve (quote foo))))
test-project.core=> (def&resolve foo bar)
#'test-project.core/bar
test-project.core=> foo
12
test-project.core=> bar
#'test-project.core/foo
If you actually want to get value of foo into the bar, then you have to deref (#) var you get by resolving:
(defmacro def&resolve
[a b]
`(do
(def ~a 12)
(def ~b #~`(resolve '~a))))
test-project.core=> (def&resolve foo bar)
#'test-project.core/bar
test-project.core=> bar
12

Comparison based on Clojure types

I have the following record type that I am trying to test:
(defrecord FirstOrderState [datum matrix]
State
;; implementation goes here ...
)
I am trying to branch based on the above type, but am not getting the results I need
(def state (->FirstOrderState datum matrix))
(= (type state) composer.algorithm.markov.state.FirstOrderState)
=> false
However, looking at the type of state confirms that it should match:
(type state)
=> composer.algorithm.markov.state.FirstOrderState
This seems like it should work, as a similar check results in true:
(= (type []) clojure.lang.PersistentVector)
=> true
What is it that I am missing here? Using the below hack provides a solution, but not very elegant:
(= (str (type state)) (str composer.algorithm.markov.state.FirstOrderState))
=> true
My first guess would be that you have reloaded the namespace containing the definition of the record type and that state is defined elsewhere (possibly at the REPL), and so composer.algorithm.markov.state.FirstOrderState now refers to a different class from the one it used to at the time when state was created.
Demo at the REPL:
user=> (defrecord Foo [])
user.Foo
user=> (def foo (->Foo))
#'user/foo
user=> (= (type foo) Foo)
true
user=> (defrecord Foo [])
user.Foo
user=> (= (type foo) Foo)
false

is it possible to have type hints without LET?

This is my code (an example):
(def foo (.java_method java_object))
(debug "result of method bar() on object foo: " (.bar foo))
I get a warning (foo is of type FooType in Java):
Reflection warning, example/test.clj:2 - call to bar can't be resolved
I can remove the warning with this type hint:
(def foo (.java_method java_object))
(debug "result of method bar() on object foo: " (.bar ^FooType foo))
This works, but I have to do this type hinting every time I use foo. Another solution would be to use let, but it creates extra indentation level, which I'd like to avoid. Is it possible to do something like?:
(def foo (.java_method java_object))
(set-type foo FooType)
(debug "result of method bar() on object foo: " (.bar foo))
No. For associating compile-time metadata like type-hints with named values, use let.
You can associate type hint with def.
(def ^FooType foo (.java_method java_object))
UPDATE:
Example:
user=> (set! *warn-on-reflection* true)
true
user=> (import java.util.Hashtable)
java.util.Hashtable
user=> (def ^Hashtable table (Hashtable.))
#'user/table
user=> (.put table "one" 1)
nil
user=> (.put table "two" 2)
nil

What information does clojure's extends? really give me?

I recently asked why interfaces and protocols could be incompletely implemented in clojure:
user=> (defprotocol P (foo [self]))
P
user=> (extend-type Long P)
nil
user=> (extends? P Long)
true
user=> (foo 1)
IllegalArgumentException No implementation of method: :foo of protocol: #'user/P found for class: java.lang.Long clojure.core/-cache-protocol-fn (core_deftype.clj:527)
and was told that this was for interop reasons and that it wouldn't be a problem in practice. Sure.
But apparently extends? really tells me nothing about the relationship between a protocol and a class: just as (extends? P C) does not imply that I can call foo on objects of class C, (not (extends? P C)) does not imply that I cannot call foo on objects of class C:
user=> (defprotocol P (foo [self]))
P
user=> (extend-type Object P (foo [self] 1))
nil
user=> (extends? P Long)
false
user=> (foo 1)
1
Now I am very confused about what information extends? is supposed to give me... satisfies?, on the other hand, handles the second case correctly, but not the first one.
When in doubt check the code :). The implementation of extends? is this:
(defn extends?
"Returns true if atype extends protocol"
{:added "1.2"}
[protocol atype]
(boolean (or (implements? protocol atype)
(get (:impls protocol) atype))))
So it just check if the atype has been extended by the protocol and it doesn't mean it has implemented all the methods of the protocol.
The :impls is a map where key is the type that extended the protocol and the value is map which has the methods implementation of the protocol for the type.
user=> (defprotocol hello (a [self]))
hello
user=> (:impls hello)
nil
user=> (extend-type String hello)
nil
user=> (:impls hello)
{java.lang.String {}}
user=> (extend-type String hello (a [self] 10))
nil
user=> (:impls hello)
{java.lang.String {:a #<user$eval613$fn__614 user$eval613$fn__614#1d978ea>}}
On the other hand to satisfies? you need to pass the object on which you want to check for protocol and not the type as in case of extends? So if you look at satisfies? code it is a bit more complex then extends as it has to check the base classes of the object being passed for being extended by protocol. But both the functions just check whether there the type (or base types) has extended the protocol or not AND they don't check if you have actually implemented the protocol methods or not.

Clojure: Adding functions to defrecord without defining a new protocol

I'm used to OO in python/java. Doing Clojure now. I came across defrecord, but it seems like I have to define a protocol for each function or set of functions I want the record to implement. Creating a new protocol creates friction. I have to name not only the function I want, but the protocol. What I'am looking for is a way to "nicely" associate a function with a record so that the function has access to the record's parameters via the this parameter, without having to define a new protocol or add a function to an existing protocol.
If you haven't tried multimethods yet, they may be closer to what you are looking for.
Define:
(defrecord Person [first middle last])
(defmulti get-name class)
(defmethod get-name Person [person] (:first person))
Use:
(def captain (Person. "James" "T" "Kirk"))
(get-name captain)
The multimethod implementation that is chosen is based on the dispatch function in defmulti (a function that takes the args passed to the function and returns a dispatch value). Quite commonly "class" is the dispatch function, as here, to dispatch on type. Multimethods support multiple independent ad-hoc or Java-based type hierarchies, default implementations, etc.
In general though, I think perhaps you might want to take a step back and consider whether you really want either protocols or multimethods. You seem to be trying to "do OO" in Clojure. While aspects of OO (like polymorphism) are great, maybe you should try thinking in alternate ways about your problem. For example, in the example I just gave, there is no compelling reason (yet) to implement get-name polymorphically. Why not just say:
(defn get-name [x] (:first x))
Do you even need a Person record at all? Would a simple map suffice? Sometimes the answers are yes, sometimes no.
In general Clojure does not provide class inheritance. You can certainly build an equivalent (even with protocols) if you really want it but generally I find there are other better ways of solving that problem in Clojure.
Excellent question.
As usual, there's a beautiful way to do things in Clojure - here's how to implement your own simple dynamic OO system (including inheritance, polymorphism and encapsulation) in 10 lines of Clojure.
The idea: You can put functions inside normals Clojure maps or records if you want, creating an OO-like structure. You can then use this in a "prototype" style.
; define a prototype instance to serve as your "class"
; use this to define your methods, plus any default values
(def person-class
{:get-full-name
(fn [this] (str (:first-name this) " " (:last-name this)))})
; define an instance by merging member variables into the class
(def john
(merge person-class
{:first-name "John" :last-name "Smith"}))
; macro for calling a method - don't really need it but makes code cleaner
(defmacro call [this method & xs]
`(let [this# ~this] ((~method this#) this# ~#xs)))
; call the "method"
(call john :get-full-name)
=> "John Smith"
; added bonus - inheritance for free!
(def mary (merge john {:first-name "Mary"}))
(call mary :get-full-name)
=> "Mary Smith"
Using the idea of mikera I developed a way to have this (OO-like classes)
;; -----------------------------------------
;; main()
;; -----------------------------------------
(def p1 (newPoint 3 4))
(def p2 (newPoint 0 0))
(call p1 :getY) ;; == 4
(call p1 :distance p2) ;; == 5
Complete example, with a "decent and organized" way to declare a OO-like class
;; -----------------------------------------
;; begin Point class
;; -----------------------------------------
(defrecord Point [x y methods] )
(def someMethods
{
:getX (fn [this] (:x this) )
:getY (fn [this] (:y this) )
:distance (fn [this other]
(def dx (- (:x this) (:x other)))
(def dy (- (:y this) (:y other)))
(Math/sqrt (+ (* dx dx) (* dy dy) ))
)
}
)
;;
;; Point constructor
;;
(defn newPoint [x y]
(Point. x y someMethods)
)
;; -----------------------------------------
;; end Point class
;; -----------------------------------------
;; -----------------------------------------
;; helper to call methods
;; -----------------------------------------
(defn call
([obj meth] ((meth (:methods obj)) obj))
([obj meth param1] ((meth (:methods obj)) obj param1))
([obj meth param1 param2] ((meth (:methods obj)) obj param1 param2))
)
;; -----------------------------------------
;; main()
;; -----------------------------------------
(def p1 (newPoint 3 4))
(def p2 (newPoint 0 0))
(call p1 :getY) ;; == ((:getX (:methods p1)) p1)
(call p1 :distance p2) ;; == ((:distance (:methods p1)) p1 p2)