The difference between -toString vs .toString in Clojure

clojure, java

Solution

First, some terminology:

`(.toString (some.Example.))` is a call to the `toString` method of the newly constructed `some.Example` instance.

`(-toString (some.Example.))` is a regular Clojure function call, with `-toString` being the name of a Clojure Var storing a function and `(some.Example.)` being its sole argument.

`:gen-class` arranges things so that the `-toString` Var backs the `toString` method; that is, any call to the `toString` method of a `some.Example` instance results in a call to `-toString`. So it is indeed the case that just calling `-toString` directly is equivalent.

However, before you can call a Clojure function by referring to the Var in which it's stored, you need to make sure the namespace in which this Var lives has been loaded (not a problem here, given that you were able to construct an instance of `some.Example`) and then either refer to the Var by its fully-qualified name, or else use `refer`, `use`, `require` or `alias` to make it possible to refer to it by a shorter name:

(some.Example/-toString ...)

(use '[some.Example :only [-toString]])
(-toString ...)

(require '[some.Example :refer [-toString]])
(-toString ...)

(require '[some.Example :as se])
(se/-toString ...)

;; refer and alias are typically not used directly

If you say `-toString` without first using `refer`, `use` or `require` as shown above1, Clojure will attempt to resolve the symbol `-toString` to a Var in the current namespace (typically `user` in REPL sessions; with `lein repl` it may be the `:main` namespace from your `defproject` form).

1 That's speaking about the REPL. In a source file, you'd typically use `:use` or `:require` in your `ns` form; the syntax is the same as for `use` / `require` minus the quoting.

Problem

Following the explanation about `:gen-class` in The Anatomy of `gen-class`, I used `leiningen` to get the class files. - `leon new pinger` to create a project. - `cd src` and `mkdir some` and created a `Example.clj` file in it. - Added `:aot [some.Example]` (or `:aot :all`) in `project.clj`. The Example.clj is as follows: ``` (ns some.Example (:gen-class)) (defn -toString [this] "Hello, World!") ``` Then I executed `lein compile` to get the classes in `target` directory. Then, I was executing this code with `lein repl`. ``` (-toString (some.Example.)) ; should return "Hello, World!" ``` However, I got this error message. ``` CompilerException java.lang.RuntimeException: Unable to resolve symbol: -toString in this context, compiling:(/private/var/folders/nw/dmb7jh3d2hq89296z2gnntqm0000gn/T/form- init7145760420048735997.clj:1:1) ``` `.toString` works fine. ``` user=> (.toString (some.Example.)) "Hello, World!" ``` The website explains that I should get the same results from both `-toString` and `.toString`, but I got only correct results with `.toString`. What's the difference between `-toString` and `.toString` in Clojure? Why `-toString` raises an error in the example?

Original source