Java arrays in Clojure's gen-interface - clojure

I have this piece of code:
(ns com.example.main)
(gen-class
:name com.example.main.CTest
:methods [ [foo [] "[B"]])
(defn -foo [this]
(byte-array [(byte 1) (byte 2)]))
(gen-interface
:name com.example.main.ITest
:methods [ [foo [] "[B"]])
It creates the foo method in class CTest correctly, with return type byte[]. However, the same thing creates a method with return type [B in the ITest interface. How do I do this correctly? Is it a bug in Clojure?
Thanks, David

I don't know if some other solution is preferred, but this works:
(gen-interface
:name com.example.main.ITest
:methods [[foo [] #=(java.lang.Class/forName "[B")]])

Related

Using clojure protocol across multiple namespaces

I'm currently implementing multiple types with the same protocol as the basis and would like to reduce the number of files one would need to include in the namespace in order to use them. To give an example:
basetype.clj
(defprotocol Base
(do-something [obj]))
(deftype Basetype [obj]
...
Base
(do-something [obj] something-something))
second_type.clj
(ns project.second-type
(:use project.basetype))
(deftype DifferentType [obj]
...
Base
(do-something [obj] something-slightly-different))
What I did achieve is that everything built for Basetype also works with DifferentType. However, I'd like to access the function do-something simply by including second_type.clj in a namespace instead of including both. Is there a way to achieve this?
as i mentioned in my comment, you should be able to reexport any values from any namespace.
you could make up simple function like this:
(defn reexport [from-ns name]
(ns-unmap *ns* name)
(intern *ns* name #(ns-resolve from-ns name)))
(reexport 'project.basetype 'do-something)
or to reexport all the values from the given ns:
(defn reexport-all [from-ns]
(run! (partial reexport from-ns) (map first (ns-publics from-ns))))
(reexport-all 'project.basetype)
in repl:
user> (ns x)
nil
x> (defn f [v] (inc v))
#'x/f
x> (ns y)
nil
y> (user/reexport 'x 'f)
#'y/f
y> (in-ns 'user)
#namespace[user]
user> (y/f 10)
11
user> (in-ns 'y)
#namespace[y]
y> (defn f2 [v] (dec v))
#'y/f2
y> (ns z)
nil
z> (user/reexport-all 'y)
nil
z> (in-ns 'user)
#namespace[user]
user> (z/f 1)
2
user> (z/f2 1)
0

How do I compose two deftypes into a new deftype when they all live in different files?

The following works in the repl:
(defprotocol MyProtocol
(foo [this]))
(deftype A []
MyProtocol
(foo [this] "a"))
(deftype B []
MyProtocol
(foo [this] "b"))
(deftype C []
MyProtocol
(foo [this] (str (foo (A.)) (foo (B.)))))
When I try to move each instance to a separate file to reduce coupling, then I get the following error on C: "Unable to resolve symbol: foo in this context"
Sample layout:
;; my_protocol.clj
(ns my-protocol)
(defprotocol MyProtocol
(foo [this]))
;; type_a.clj
(ns type-a
(:require my-protocol :refer [MyProtocol])
(deftype A []
MyProtocol
(foo [this] "a"))
;; type_b.clj
(ns type-b
(:require my-protocol :refer [MyProtocol])
(deftype B []
MyProtocol
(foo [this] "b"))
;; type_c.clj
(ns type-c
(:import [type_a A]
[type_b B])
(:require my-protocol :refer [MyProtocol])
(deftype C []
MyProtocol
(foo [this] (str (foo (A.)) (foo (B.)))))
(ns type-a
(:require my-protocol :refer [MyProtocol])
You refer to the protocol, but never to foo, so when you attempt to call foo the compiler doesn't know what you mean. Instead write:
(ns type-a
(:require my-protocol :refer [MyProtocol foo])

When to use alter-var-root with (constantly)?

I encountered something like this in a program:
(defonce foo nil)
(alter-var-root #'foo (constantly 4))
Since the code above uses constantly, is there any reason to prefer it to a simple def, like below?
(def foo 4)
Is it just to make it more consistent with the defonce, or there are downsides to using def?
(ns banana)
(defonce foo nil)
(ns user)
(use 'banana)
foo ;=> nil
(alter-var-root #'foo (constantly 42))
foo ;=> 42
(def foo 50)
CompilerException java.lang.IllegalStateException: foo already refers to: #'banana/foo in namespace: user

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: how to create a record inside a function?

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.