Hi everyone. I have some questions about objects which respond true
to the clojure class?
function. First of all what is the correct word to use to describe the set of objects for which class?
returns true
? I want to call them "classes" but sometimes people complain that interfaces are not classes.
The Java Virtual Machine specification (separate from the Java language specification, which specifies Java source code) uses the names classes and interfaces, e.g. you can find occurrences of both in the table of contents here: https://docs.oracle.com/javase/specs/jvms/se8/html/
The Java documentation for the class java.lang.Class
says near the beginning: "Instances of the class `Class` represent classes and interfaces in a running Java application." -- https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Class.html
interesing. so the word "Class" with a capital C includes classes and interfaces ?
class is used both as a generic name (including interfaces) and as a specific thing (concrete classes distinct from interfaces) depending on context, but yes Class includes both
And the phrase "class and interface" and "class or interface" is sprinkled all over that last documentation page I linked.
the set of objects of class java.lang.Class
?
there are also arrays, which are objects but somewhat outside typical classes, and primitives
it's hard to talk about the world with a limited number of words which different people attach different semantics to.
ain't that the truth
Hence the use of short phrases and definitions of terms within a document that needs to make precise distinctions that are not often made casually.
OK, 2nd question. Can someone give me an example of two interfaces (which I can reference by name in clojure such as java.lang.Comparable
or <http://java.io|java.io>.Serializable
) which are incompatible in the sense that they both have a member with the same name and the same parameter types?
i.e. two interfaces which are guaranteed never to be simultaneously in the ancestors list of any one Class (with a capital C)
If no one knows, one way to attempt to answer the question is to run some code that scans the JVM's internal state to try to find all current instances of java.lang.Class
, keeps only the ones that represent interfaces, and write some code that collects together all of their method names and signatures, looking for similar ones.
I have some Clojure code somewhere I can probably link to that uses a library written by someone else to look for all (or at least most) instances of java.lang.Class
in a running JVM. I haven't written code to do the latter part, but it should be straightforward to write given a collection of instances of java.lang.Class
I tried to find the descendants of Object, but that doesn't work. If it did I could find all descendants, then fall all their ancestors. Since interfaces won't be descendants, but gathering all the ancestors would find a huge number of interfaces.
😞
@andy.fingerhut indeed, given a collection of a large number of instances of java.lang.Class
, yes I would have a good chance of finding such interfaces.
The JVM set of classes and interfaces is by design very dynamic, and they can be loaded/created by a myriad of different ClassLoader objects, and there are security mechanisms to try to hide the existence of some from different "places" in the system, so there are varying degrees of completeness you can achieve with such a list, depending on how you do it.
It might be an hour or three before I find the code I wrote (away from that laptop right now)
you could skim the javadoc index
https://docs.oracle.com/en/java/javase/11/docs/api/index-files/index-1.html
like abort() is a "method in interface" for many interfaces, probably not all the same hierarchy
http://java.net.http.WebSocket and javax.security.auth.spi.LoginModule
accept(<foo>)
add(<foo>)
probably pick any common verb :)
http://java.net.http.WebSocket seems to be both :abstract and also :interface
all interfaces are abstract
ah ha, but not all abstracts are interfaces?
correct
promise?
abstract classes can't be instantiated
they have to be subclassed and made non-abstract (usually by overriding abstract methods)
what does it mean if a Class is not :abstract, and not :interface, and not :final ?
does it work the same as abstract but can be instantiated?
If it is none of those, that is probably the most common kind of class that people learn to create in Java first. It is a class, not an interface. It is not declared abstract, so you can use new
to construct instances of that class. It is not final
, so you can define subclasses of it if you wish.
interface -> it is a Java interface (implies abstract, and I believe never final), abstract -> cannot construct instances of it. final -> cannot declare subclasses of it
ahhh, so these are common ?
not exotic?
Having none of those three flags present is common
do we have examples of those in clojure other than Object ?
Object is the one that I have seen. and I've made a special case of it. but if this is common, I need to understand it better, perhaps.
clojure.lang.PersistentVector
java.lang.Object is in every JVM, whether Clojure is running or not. It is the class from which all other classes are sub-classes (perhaps through a chain of multiple other intermediate classes)
great.. is there some class which inherits from clojure.lang.PersistentVector
?
If you go through the source directory here, you can probably find a bunch, all in the clojure.lang package: https://github.com/clojure/clojure/tree/master/src/jvm/clojure/lang
ie. a subclass of clojure.lang.PersistentVector
?
I do not know of any off hand. Perhaps not in Clojure itself, but some third party library very well might.
again if it were possible to walk the instances of java.lang.Class
I could programmatically find such cases.
@jimka.issy FWIW, most things that need to be "vector-like" extend APersistentVector
which is:
public abstract class APersistentVector extends AFn implements IPersistentVector, Iterable,
List,
RandomAccess, Comparable,
Serializable, IHashEq {
Then PersistentVector
extends that and implements a few extra interfaces:
public class PersistentVector extends APersistentVector implements IObj, IEditableCollection, IReduce, IKVReduce{
clojure-rte.rte-core> (:flags (refl/type-reflect clojure.lang.PersistentVector))
#{:public}
clojure-rte.rte-core> (:flags (refl/type-reflect clojure.lang.APersistentVector))
#{:public :abstract}
clojure-rte.rte-core> (:flags (refl/type-reflect clojure.lang.IPersistentVector))
#{:interface :public :abstract}
clojure-rte.rte-core>
Can someone suggest a better name for this function? The function takes a class-name such as the symbol Number
, uses resolve
to get the class and then uses (comp :flags efl/type-reflect)
to get a list of flags. Then returns a keyword from :abstract
, :interface
, :final
, :public
. My function has a really bad name at the moment. I need a better name for this.
(defn-memoized [class-type -class-type]
"Takes a class-name and returns either :abstract, :interface, :public, or :final,
or throws an ex-info exception."
[t]
(let [c (find-class t)
r (refl/type-reflect c)
flags (:flags r)]
(cond
(= c Object) ; case #1
:abstract
(contains? flags :interface) ; case #2
:interface
(contains? flags :final) ; case #3
:final
(contains? flags :abstract) ; case #4
:abstract
(= flags #{:public}) ; case #5
:public
:else
(throw (ex-info (format "disjoint? type %s flags %s not yet implemented" t flags)
{:error-type :invalid-type-flags
:a-type t
:flags flags})))))
BTW, the function makes a special case of Object
, when I'm still not sure is correct for my application. The more I think about it, the more I think case 1 and 5 should be merged into a single case. That might change in the future when I understand the situation better.@seancorfield do you know of a subclass of clojure.lang.PersistentVector
)
such would be great for a test case of my code
I found an interesting one:
clojure-rte.rte-core> (:flags (refl/type-reflect BigInteger))
#{:public}
clojure-rte.rte-core>
What's "interesting" about BigInteger
@jimka.issy?
I found some code that I have used in the past to list most/all classes in a running JVM, but in trying to run it today I seem to have lost the recipe for what command line options when starting the JVM it requires to have the right privileges to work properly. It is some test code in this repository: https://github.com/jafingerhut/cljol
A tiny shell script that might work with some operating system / JDK versions, or did at one point, is in the file doc/generate-report.sh
It loads and runs a function named report
in this namespace: https://github.com/jafingerhut/cljol/blob/master/src/clj/cljol/reflection_test_helpers.clj
it uses this library to do the actual finding of Java classses and I believe also interfaces: https://github.com/classgraph/classgraph
all of the A...
types in clojure are generally base classes, I would guess most are abstract
Here is a short sample use of calling the classgraph library from Clojure, with no other libraries required except classgraph and those included with Clojure: https://github.com/jafingerhut/cljol/blob/master/doc/sample-classgraph-use.clj
and and I... classes are interfaces?
yes, that's a common Java idiom
(the A... is not, but it's common in the Clojure code base)
which is not to say that it's totally followed - things like Countable are interfaces too