java

2020-12-20T22:52:49.139100Z

This is confusing me -- hoping someone knows how to figure out what is happening here. Here is the deftype from Clojure's implementation for the type clojure.core.VecSeq: https://github.com/clojure/clojure/blob/master/src/clj/clojure/gvec.clj#L59-L165

2020-12-20T22:54:30.140500Z

I see methods there named iterator, hasheq, equals, hashCode, and many more, but let us focus on those for a moment. When I evaluate a form to try to determine all methods of the class clojure.core.VecSeq, those method names do not appear:

user=> *clojure-version*
{:major 1, :minor 10, :incremental 1, :qualifier nil}
user=> (pprint (map #(.getName %) (seq (.getDeclaredMethods clojure.core.VecSeq))))
("count"
 "next"
 "empty"
 "first"
 "cons"
 "cons"
 "seq"
 "chunkedNext"
 "chunkedFirst"
 "chunkedMore"
 "getBasis"
 "equiv"
 "internal_reduce"
 "more")

2020-12-20T22:55:44.141300Z

Part of the Java docs for getDeclaredMethods says "Returns an array containing `Method` objects reflecting all the declared methods of the class or interface represented by this `Class` object, including public, protected, default (package) access, and private methods, but excluding inherited methods.": "https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredMethods--

2020-12-20T22:57:19.142900Z

All classes created by deftype a direct subclasses of the java.lang.Object class. But there are quite a few methods in that deftype definition linked above that are methods of interfaces that class VecSeq implements, and I thought those would all show up.

2020-12-20T22:58:40.143600Z

I guess the thing really confusing me is: why does getDeclaredMethods return those methods for clojure.core.VecSeq, but not the others that are declared in the deftype?

2020-12-20T23:00:25.145Z

I don't know for sure but my guess is Object is the only concrete class deftype allows

2020-12-20T23:00:35.145300Z

Everything else is an interface

2020-12-20T23:04:52.146500Z

Ah I see, the question is about why iterator isn't in the list

2020-12-20T23:08:11.150Z

I think it relates to your earlier question about bridge methods, my guess is those methods are all specified by more than one of the interfaces and superclass, so there is some special code generation going on, which is marking all of those methods as synthetic

2020-12-20T23:17:15.150700Z

There are other classes where getDeclaredMethods explicitly returns several bridged and/or synthetic methods, but I haven't carefully analyzed the conditions under which those occur.

2020-12-20T23:21:04.151500Z

This is also difficult to understand -- instances of the class clojure.core.VecSeq seem not to have a method iterator that Clojure can find:

user=> (def pv1 (vector-of :long 1 2 3))
#'user/pv1
user=> (def pvs1 (seq pv1))
#'user/pvs1
user=> (class pv1)
clojure.core.Vec
user=> (class pvs1)
clojure.core.VecSeq
user=> (. pv1 iterator)
#object[clojure.core.Vec$reify__8269 0x4535b6d5 "clojure.core.Vec$reify__8269@4535b6d5"]
user=> (class (. pv1 iterator))
clojure.core.Vec$reify__8269
user=> (. pvs1 iterator)
Execution error (IllegalArgumentException) at user/eval37 (REPL:1).
No matching field found: iterator for class clojure.core.VecSeq

2020-12-20T23:26:16.152200Z

that is curious, I just noticed that javap doesn't show any of the missing methods either

2020-12-20T23:28:34.153100Z

Hmmm. I may do a binary search on the deftype form of clojure.core.VecSeq to see if it has something weird to do with some error in one of the methods in the middle somewhere, that somehow causes later methods not to be compiled.

2020-12-20T23:31:57.153500Z

actually those methods are pretty new, let me make sure I am on a new enough clojure version

2020-12-20T23:33:55.153700Z

ok, there it is in javap

2020-12-20T23:34:00.154Z

public java.util.Iterator iterator();
    descriptor: ()Ljava/util/Iterator;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: new           #204                // class clojure/lang/SeqIterator
         3: dup
         4: aload_0
         5: checkcast     #6                  // class clojure/lang/ISeq
         8: invokespecial #207                // Method clojure/lang/SeqIterator."<init>":(Lclojure/lang/ISeq;)V
        11: checkcast     #209                // class java/util/Iterator
        14: areturn
      LineNumberTable:
        line 59: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      14     0  this   Lclojure/core/VecSeq;

2020-12-20T23:37:37.154300Z

Clojure 1.10.2-master-SNAPSHOT
user=> (def pv1 (vector-of :long 1 2 3))
#'user/pv1
user=> (def pvs1 (seq pv1))
#'user/pvs1
user=> (class pv1)
clojure.core.Vec
user=> (class pvs1)
clojure.core.VecSeq
user=> (. pv1 iterator)
#object[clojure.core.Vec$reify__8294 0x75201592 "clojure.core.Vec$reify__8294@75201592"]
user=> (class (. pv1 iterator))
clojure.core.Vec$reify__8294
user=> (. pvs1 iterator)
#object[clojure.lang.SeqIterator 0x438bad7c "clojure.lang.SeqIterator@438bad7c"]
user=>

2020-12-20T23:38:17.155200Z

so the methods are there, they are just very new, so you need a newish clojure build (I built that snapshot locally) to have them

2020-12-20T23:49:34.155600Z

Ugh. Yes, I may be comparing latest source code with Clojure 1.10.1 reflection results....

2020-12-20T23:51:44.156100Z

yep, that was it. Even more embarrassing since I wrote one of the patches that added one of those methods.