Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The difference between -toString vs .toString in Clojure

Tags:

java

clojure

Following the explanation about :gen-class in The Anatomy of gen-class, I used leiningen to get the class files.

  1. leon new pinger to create a project.
  2. cd src and mkdir some and created a Example.clj file in it.
  3. 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?

like image 224
prosseek Avatar asked Nov 17 '25 16:11

prosseek


1 Answers

First, some terminology:

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

  2. (-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.

like image 79
Michał Marczyk Avatar answered Nov 20 '25 07:11

Michał Marczyk



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!