4

I was searching for a Clojure logarithm function and concluded there really isn't one for v1.3+. What took me so long to invoke Math/log was this:

user=> Math/log

CompilerException java.lang.RuntimeException: Unable to find static field: log in class java.lang.Math, compiling:(NO_SOURCE_PATH:0:0)

I tried variations like (use 'java.lang.Math) and so forth. It wasn't until I tried an example that I found it's there after all:

user=> (Math/log 10)
2.302585092994046

This must be by design, but what is the reason?

1
  • Math/log is a static method. You are trying to access it as if it were a static variable. Commented Aug 5, 2015 at 22:44

3 Answers 3

6

A static method imported from Java is not a Clojure function or any other kind of Clojure object. The compiler reports any misfit as a missing field, even where the context is looking for a function. All of these ...

Math/log
(Math/log)
(map Math/log (range 1 5))

... produce such errors.

For a corresponding Clojure function:

  • inc returns the function;
  • (inc) reports ... wrong number of args(0) ...;
  • (map inc (range 1 5)) returns (2 3 4 5).

You can wrap a Java method as a Clojure one:

(defn log [x] (Math/log x))

... getting the expected result:

(map log (range 1 5))
;(0.0 0.6931471805599453 1.0986122886681098 1.3862943611198906)

The Clojure Java Interop page recommends

(map #(Math/log %) (range 1 5))

... in such cases.

Sign up to request clarification or add additional context in comments.

Comments

4

Clojure provides some forms for interoperating with Java classes, methods, and fields. When you access static field in a class, you can do it like this:

user=> Integer/MAX_VALUE
;=> 2147483647
user=> Math/PI
;=> 3.141592653589793

And when you want to invoke static method, you can use the following form

user=> (Math/log 10)
;=> 2.302585092994046
user=> (Math/sin 1)
;=> 0.8414709848078965

When you try to evaluate just Math/log, clojure think it's static field, which is not true.

user=> Math/log

;=> CompilerException java.lang.RuntimeException: Unable to find static field: log in class java.lang.Math, compiling:(/private/var/folders/jh/q738l9dn0hxg0vvwbty7m5hw0000gp/T/form-init145007798854806400.clj:1:5845)

You can see it from the error message(Unable to find static field:...) that the clojure REPL try to find static field log from Math class, then failed.

Comments

1

In Java, one uses parentheses to invoke a function:

println("hi");

Clojure also uses parentheses to invoke a function, but with a different placement:

(println "hi")

In either Java or Clojure, just typing:

println

is an error, because you don't have the parentheses to indicate a function call.

In your first example, you use the name of the function Math/log, but you had no parentheses to tell the REPL that you wanted to invoke a function.

Also, in Java, parentheses can indicate either a function call or a grouping operator:

println(2 + (3 + 4))

In Clojure, parentheses only indicate function calls, and never indicating simple grouping.

2 Comments

In Clojure typing println is not an error. It just evaluates to the function itself.
In clojure functions are also data (symbols) of type IFn, which is why you don't get an error. Java methods do not share this property though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.