Clojure: invoking multiple arity functions - clojure

I have a problem invoking the multiple arity function printf on java.io.PrintWriter (specifically, System.out).
user=> (.printf System/out (into-array Object ["foo"]))
IllegalArgumentException No matching method found: printf for class java.io.PrintStream
clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:53)
user=>

Your code attempts to call method printf(Object[] arg) of java.io.PrintStream class. But such method doesn't exist. Propably you want to call this one printf(String format, Object ... args) like this:
(.printf System/out "arg1: %s" (into-array Object ["foo"]))
=> #<PrintStream java.io.PrintStream#708e4544>
arg1: foo
Here #<PrintStream java.io.PrintStream#708e4544> is an object returning from printf.

Related

Casting nil in Clojure

I want to call an overloaded Java method from Clojure, and passing in null (or nil in Clojure) has special meaning. How would I ensure that the correct Java method is called if the argument is nil?
e.g. suppose the overloaded Java methods were as follows:
public class Foo {
public String bar(String s) {
return (s == null) ? "default" : s;
}
public String bar(Integer i) {
return (i == null) ? "0" : i.toString();
}
}
I want to yield the value "default", so I want to do the following in my Clojure code:
(.bar (Foo.) (cast String nil))
I've tested this in two slightly different environments and I do not get consistent results. And it appears that casting a nil value in Clojure does not yield the expected type, e.g. --
(type (cast String nil))
; => nil
cast doesn't do what you think it just ensures the second argument is of the specified class and returns it (the 2nd argument, not the class) or throws an exception.
You need to add a type hint but you can't add it directly to nil:
=> (String. nil)
CompilerException java.lang.IllegalArgumentException: More than one matching method found: java.lang.String
Here I have an exception because nil matches too many overloads and the compiler doesn't know which to pick.
=> (let [^String cnil nil] (String. cnil))
NullPointerException java.lang.String.<init> (String.java:152)
Here I have an exception but from the constructor: the type hint allowed the compiler to select the proper overload (which overload complains about being passed a nil...).

Clojure: how to invoke static method main from Java class loaded by URLClassLoader

I want to load Java class using URLClassLoader and invoke method main. The code below gives an error at the last line and I can not figure out how to fix it.
(def classloader (URLClassLoader. (into-array files)))
(def classname "example.Test")
(def clazz (.. classloader (loadClass classname)))
; I assume not the most effective way to get method "main"
; additional feedback appreciated
(def method (first (filter #(= (. % getName) "main") (. clazz getMethods))))
(def args (make-array String 1))
; specify single command line argument for method main(String[]args)
(aset args 0 "my-file")
; attempt to invoke static method using Java reflection API fails.
(. method invoke nil args)
Exception in thread "main" java.lang.IllegalArgumentException:
argument type mismatch, compiling:
Please note that the class is not otherwise available in the default classloader, so
(example.Test/main "myfile")
would fail.
Thank you,
Pavel
You are confusing the signature of invoke with the signature of the main method.
The signature of "main" is (String[] args1)
The signature of "invoke" is (Object obj, Object... args2)
args2 should be an array with one item per each param in the main method, so it should be an array of 1 element, the element being the String[]. So:
(def invoke-args (into-array Object [args]))
(. method invoke nil invoke-args)
About a simpler way of finding "main" look at http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getMethod(java.lang.String,%20java.lang.Class...)
I summarized the result of the discussion below. (Thanks to dAni for help).
(let
[classname "example.Test"
clazz (.. classloader (loadClass classname))
method (. clazz getMethod "main" (into-array Class [(class (into-array String []))]))
args (make-array String 1)]
(aset args 0 "my-file")
(. method invoke nil (into-array Object [args])))

Does hinting return types in protocols have any effect within Clojure?

You can hint a return type in a protocol
(defprotocol Individual
(^Integer age [this]))
and the compiler will make your methods comply:
(defrecord person []
Individual
(^String age [this] "one"))
; CompilerException java.lang.IllegalArgumentException: Mismatched return type: age, expected: java.lang.Object, had: java.lang.String, ...
But you don't have to honour the type-hint:
(defrecord person []
Individual
(age [this] "one"))
(age (new person))
; "one"
Does the type-hint have any effect?
This is a follow up to Can you specify the return type of a method in a clojure defrecord?
The return type hint goes to the protocol function age as tag. From there, the tag is used in local type inference. To observe this in action:
- (.longValue (age (new person)))
ClassCastException java.lang.String cannot be cast to java.lang.Integer
net.bendlas.lintox/eval18038 (form-init4752901931682060526.clj:1)
;; longValue is a method of Integer, so a direct cast has been inserted
If the type hint had been left off, or if you call a method not on the hinted type, the compiler inserts a (slow) call into the reflector, instead of the plain cast:
- (.otherMethod (age (new person)))
IllegalArgumentException No matching field found: otherMethod for class java.lang.String clojure.lang.Reflector.getInstanceField (Reflector.java:271)

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

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.