Hi Marshall, Yes, that's the gist of it. If you look at the bytecode for the defrecord, you should see something like:
// Method descriptor #287 ()I // Stack: 1, Locals: 1 public int hashCode(); 0 aload_0 [this] 1 checkcast clojure.lang.IPersistentMap [18] 4 invokestatic clojure.lang.APersistentMap.mapHash(clojure.lang.IPersistentMap) : int [303] 7 ireturn Line numbers: [pc: 0, line: 1] [pc: 4, line: 1] Local variable table: [pc: 0, pc: 7] local: this index: 0 type: user.R1 // Method descriptor #305 (Ljava/lang/Object;)Z // Stack: 3, Locals: 2 public boolean equals(java.lang.Object G__1432); 0 aload_0 [this] 1 checkcast clojure.lang.IPersistentMap [18] 4 aload_1 [G__1432] 5 aconst_null 6 astore_1 [G__1432] 7 invokestatic clojure.lang.APersistentMap.mapEquals(clojure.lang.IPersistentMap, java.lang.Object) : boolean [309] 10 ireturn which calls the code at [1] and [2]. The bytecode I saw for deftype did not override either, so you should get the default from Object [3][4], which just does comparison by identity for equals, and the default hashing method. (Uses a native code call in what I'm seeing for java.lang.Object's Java source via Netbeans, and javadocs say it hashes the pointer address as you mentioned). I'd say your assessment about hashing/identity and performance is correct in regards to defrecord/deftype. On the other hand, it's good to have correct value-based hashing out of the box with defrecord, IMO. I guess the choice to use one or the other should keep the equals/hashCode stuff in mind, and whether you need things to be value-based or not. As a side note, as an experiment I just tried overriding Object.equals and Object.hashCode with a defrecord, and I got a compiler error: CompilerException java.lang.ClassFormatError: Duplicate method name&signature in class file user/R1, compiling:(/private/var/folders/0k/xj_drd990xxf4q99n2bdknrc0000gn/T/form-init3397614882621384237.clj:1:1) I'm assuming that defrecord is adding its hashCode and equals implementations without checking if it's being overridden, but haven't verified. (That was with 1.7.0-beta3 at least). Cheers! steven [1] - https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java#L103-L112 [2] - https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentMap.java#L52-L71 [3] - http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#hashCode() [4] - http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object) On Tue, Jun 2, 2015 at 11:28 PM, Mars0i <marsh...@logical.net> wrote: > Steven--Oops, yeah, I am calling Java methods that are probably using > hashCode(), and maybe equals(). Interesting. > > Is the idea that records are hashed on the values in their fields, while > deftype object are just hashed a pointer (or whatever identical? > uses)--something like that? So if you want fast hashing by raw identity, > you should not use defrecord? > > > > On Tuesday, June 2, 2015 at 8:10:04 PM UTC-5, Steven Yi wrote: >> >> I'm not aware of anything that would lead to significant differences in >> regards to the function call. As a test, I defined an interface and used >> deftype and defrecord, then used no.disassemble[1] to inspect the results, >> using the following commands: >> >> user=> (use 'no.disassemble) >> >> user=> (definterface P (testfn [])) >> >> user=> (defrecord R1 [x y] P (testfn [this] (reset! x (inc @y)) (reset! y >> (inc @x)))) >> >> user=> (deftype R2 [x y] P (testfn [this] (reset! x (inc @y)) (reset! y >> (inc @x)))) >> >> user=> (println (disassemble R1)) >> >> user=> (println (disassemble R2)) >> >> Looking at the bytecode for the testfn() function for both R1 and R2, >> they're pretty much identical (same opcodes). >> >> My hunch is that your performance issues may lie elsewhere. >> >> Just a random guess, are you by chance doing anything with the record/type >> that would require calling the equals() or hashCode() functions? defrecord >> would be doing a bit more work there than deftype, which gets the default >> equals/hashcode. >> >> Hope that helps! >> steven >> >> >> [1] - https://github.com/gtrak/no.disassemble/ >> >> On Tuesday, June 2, 2015 at 1:08:13 PM UTC-4, Mars0i wrote: >>> >>> I have an application using Java interop, in which I can define a class >>> using either deftype or defrecord. It has one field, containing an atom >>> containing a double, and a few methods. One of the methods is specified by >>> an interface defined in Java, and that method is called from Java. This >>> method is called many times in an inner loop. I don't use any of the extra >>> functionality provided by defrecord, but in otheri, similar programs, I >>> will. >>> >>> When I use defrecord, the speed of the program is about 25% of its speed >>> when I use deftype. This is a one-line change. I'm testing speed simply by >>> running the program for a long time, and timing it. I've done this test >>> repeatedly, so there's no reason to think the differences have to do with >>> other processes running on my machines. >>> >>> When I benchmark simple uses of defrecord and deftype using criterium, >>> they're about the same speed. >>> >>> Is there any obvious reason to think that there are situations--e.g. >>> method calls from Java--in which deftype would be expected to be >>> significantly faster than defrecord? >>> >>> I can construct a minimal example based on my program and post it here, >>> but I thought I'd check first whether there is something obvious that I >>> don't get. >>> >>> [The test I did using defrecord is below. I also replaced 'defrecord' >>> with 'deftype' and did the same test. I would think that the JIT compiler >>> wouldn't be smart enough to optimize away whatever differs between defrecord >>> and deftype, but maybe I'm wrong about that. >>> >>> (defrecord R [x y] >>> P >>> (incx2y [this] (reset! x (inc @y))) >>> (decy2x [this] (reset! y (dec @x)))) >>> >>> (def r (R. (atom 2) (atom 1))) >>> >>> (bench (def _ (dotimes [_ 50000000] (incx2y r) (decy2x r) r))) >>> ] >>> > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to a topic in the > Google Groups "Clojure" group. > To unsubscribe from this topic, visit > https://groups.google.com/d/topic/clojure/EdjnSxRkOPk/unsubscribe. > To unsubscribe from this group and all its topics, send an email to > clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.