Deepak Tatyaji Ahire
Deepak Tatyaji Ahire

Reputation: 5309

Cannot understand the parameters of the dot (`.`) special form

While testing the java interoperability, I executed - (macroexpand-1 '(.toUpperCase "deepak")) and the output was (. "deepak" toUpperCase)

Now, I came to know that . performs some sort of operation.

When I printed the doc for . using (clojure.repl/doc .), I got the output as

-------------------------
.
  (.instanceMember instance args*)
  (.instanceMember Classname args*)
  (Classname/staticMethod args*)
  Classname/staticField
Special Form
  The instance member form works for both fields and methods.
  They all expand into calls to the dot operator at macroexpansion time.

I could not understand the pattern of parameters the . expects. For example - .instanceMember

How does the parameters "deepak" and toUpperCase map to the above pattern when we execute (. "deepak" toUpperCase)?

What is instance name, class name, and instance for the expression - (. "deepak" toUpperCase)?

Upvotes: 1

Views: 96

Answers (2)

dorab
dorab

Reputation: 807

The docstring is potentially misleading - which may be the cause of your confusion.

There are two different ways to access Java interop with the "dot" form. There is Member access (.toUpperCase "deepak"), and there is the dot special form (. "deepak" toUpperCase). The docstring you showed is for Member access (.toUpperCase "deepak"), whereas the form you were looking at is the dot special form (. "deepak" toUpperCase). It is preferable that you use the Member access style of interop in most cases. Internally, the Member access style of interop is translated into the dot special form (as you found by doing the macroexpand-1).

So, in the case of (.toUpperCase "deepak"), using the docstring for Member access (.instanceMember instance), the correspondences are:

  • instanceMember maps to toUpperCase
  • instance maps to "deepak"

Upvotes: 0

Alan Thompson
Alan Thompson

Reputation: 29958

You are delving into internal details of Clojure here. This is normally not required (& usually not useful).

An expression like (.toUpperCase "deepak") calls the method "toUpperCase" on the java.lang.String object "deepak", eg

(.toUpperCase "deepak") => "DEEPAK"

The compiler translates the above internally into

(. "deepak" toUpperCase) => "DEEPAK"

which of course has the same result. You can find more information in the docs for The Dot Special Form

The docs are sometimes hard to read, but you can decipher it with a little pattern matching. In the above example, .toUpperCase is ".instanceMember" and "deepak" is the "instance" that is of type java.lang.String.

For (.getName String), the symbol String (shorthand for java.lang.String) is the "Classname". In the docs args* is a regex-like shorthand for saying zero-or-more arguments may be needed (the previous examples have zero args required).

Was there something else you wanted to accomplish?


P.S.

"When in doubt, ask the compiler."

I struggled with similar questions when I was learning Clojure, getting confused by docs & books that were incomplete or ambiguous. I later learned it was MUCH faster & much more educational to try simple experiments to fill in the blanks.

I think simple code snippets are easier/faster than the REPL:

(ns tst.demo.core
  (:use tupelo.core tupelo.test))

(dotest
  (spyx (.toUpperCase "deepak"))
  (spyx (. "deepak" toUpperCase))
  (spyx (type "deepak"))
  )

using my favorite template project, with result

-----------------------------------
   Clojure 1.10.3    Java 17.0.1
-----------------------------------

Testing tst.demo.core
(.toUpperCase "deepak")    => "DEEPAK"
(. "deepak" toUpperCase).  => "DEEPAK"
(type "deepak")            => java.lang.String

Also,

(.getName String)             => "java.lang.String"
(.getName java.lang.String).  => "java.lang.String"

Note carefully the presence/absence of double-quotes.

Upvotes: 3

Related Questions