class weirdness

20 views
Skip to first unread message

Stuart Halloway

unread,
Oct 3, 2008, 2:00:39 PM10/3/08
to clo...@googlegroups.com
Does this make sense?

user=> (let [x Integer] (.getName x))
"java.lang.Integer"
user=> (.getName Integer)
java.lang.NoSuchFieldException: getName

Stephen C. Gilardi

unread,
Oct 3, 2008, 2:50:06 PM10/3/08
to clo...@googlegroups.com
(.getName Integer) expands to (. Integer getName). "." is a special form that treats literal class names as its first argument in a special way. You can defeat that special treatment with identity:

(. (identity Integer) getName)

or the equivalent:

(.getName (identity Integer))

--Steve

Chouser

unread,
Oct 3, 2008, 2:51:19 PM10/3/08
to clo...@googlegroups.com

I hereby nominate this for the Most Asked question in Clojure. But
just because it gets asked doesn't mean it's easy to search for and
find the answer, so I'm not blaming you at all.

In Java, you can't say Integer.getName(), right? Because the Integer
class doesn't have a static getName() method. Therefore you can't say
(.getName Integer) or (. Integer getName) or (Integer/getName) in
Clojure.

Instead in Java you would have to say Integer.class.getName(), right?
But Clojure gets that class object for you automatically anytime you
try to pass it around, such as when you store it in x in your example.
So that's convenient, but sometimes you need to force it a bit, by
doing something like (.getName (identity Integer))

See also:
http://clojure-log.n01se.net/date/2008-09-06.html#09:26
http://clojure-log.n01se.net/date/2008-08-28.html#21:42
http://groups.google.com/group/clojure/browse_thread/thread/68490633c254dbd1

--Chouser

Rich Hickey

unread,
Oct 3, 2008, 2:58:37 PM10/3/08
to Clojure
This is a FAQ, but as there is no Clojure FAQ I'll try to give a
canonic answer here:

(.member x) is shorthand for (. x member)

. is a special operator. In particular, it does non-standard
evaluation of its first arg.

Because . can call static and instance methods, it determines if it is
a static call be seeing if the first arg names a class. In this case
it does:

(. Integer getName)

so it tries to find the static getName member and doesn't, because
there isn't one. You could use this syntax to call a static method on
Integer:

(. Integer parseInt "42")

Everywhere else, a classname designates the class object.

In short, if you can't say x.y() in Java you can't say (. x y) in
Clojure, and you can't say Integer.getName() in Java.

The workaround is, you really want the class object here, and to
suppress the use of Integer as a class scope:

(. (identity Integer) getName)

The above calls an instance method on an object of type Class.

The use of (. classname staticMember) should be deprecated, as we now
have the superior Classname/staticMember:

(Integer/parseInt "42")

but I think that it is a tough thing to switch to (. x member) is for
instance members only, maybe after a period of deprecation with
warnings...

Rich

Stuart Halloway

unread,
Oct 3, 2008, 3:17:46 PM10/3/08
to clo...@googlegroups.com
Thanks Stephen, Chouser, and Rich.

Understanding the historical reason that (. SomeClass method) doesn't
work, I would be in favor of the deprecation Rich mentioned, leading
to (. SomeClass method) being able to work in the future.

Cheers,
Stuart

Rich Hickey

unread,
Oct 3, 2008, 6:09:21 PM10/3/08
to Clojure
(. SomeClass method) works - it just calls static methods. We're just
talking about limiting . to instance members, which would make it work
differently.

Many of the people who get stuck on this (not you Stuart) don't even
know the difference between static methods of SomeClass and instance
methods of Class - they presume all would be available with the same
syntax! I imagine lots of complaints to the effect of, why doesn't
this work anymore:

(. Integer parseInt "42")

The flipside is, the only additional methods that you could call if I
were to change this would be the instance methods of Class. Many of
them could be made much easier with some helper functions that wrap
reflection.

If I were to change this, we would lose any static member support in
macros that leverage the . op, like .. - i.e. no more:

(.. System out (println "Hello World"))

It would _have_ to be:

(.println System/out "Hello World") or (. System/out println "Hello
World")

I much prefer treating classnames as namespaces for static members
(i.e. the latter forms), but it won't be intuitive for those used to
ClassName.staticMethod() in Java.

That may be no big deal, I don't know. I guess with a deprecation
warning in place I'd find out soon enough :)

The original design was - if you say x.y() in Java, static or
instance, you can say (. x y) in Clojure, and that idea still has the
merits of being very easy to explain, and possibly the target of
mechanical transformations of Java code.

People just got spoiled by class object literals, and now we have this
alternative non-Java-like but snazzy static member syntax.

Still mulling...

Rich
Reply all
Reply to author
Forward
0 new messages