<< Back to previous view

[CLJ-736] Docstring of defrecord (and =) does not correctly describe equality behavior for records. Created: 09/Feb/11  Updated: 01/Mar/13  Resolved: 02/Sep/11

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: Release 1.2, Release 1.3, Release 1.4
Fix Version/s: Release 1.3, Release 1.4

Type: Enhancement Priority: Minor
Reporter: Jason Wolfe Assignee: Stuart Halloway
Resolution: Completed Votes: 0
Labels: None

Approval: Accepted
Waiting On: Stuart Halloway

 Description   

http://groups.google.com/group/clojure/browse_frm/thread/eba691b38c45196b#

The docstring of defrecord says it "will define type-and-
value-based equality and hashCode". In reality, record types are included in = but not .equals (or hashCode), and so records of different types can collide as map keys.

Along the same lines, the docstring of = says "same as Java x.equals, except it ... compares numbers and collections in a type-independent manner". To me, this seems to imply the opposite of what actually happens with records.

FWIW I think it would be more clear if the behavior for = and .equals were the same in this respect, but in any case the implemented behavior should be properly documented.



 Comments   
Comment by Stuart Sierra [ 06/Jun/11 9:37 AM ]

Also discussed at https://groups.google.com/d/topic/clojure/e6UhXVny8Xc/discussion

Per Rich, "The policy is: = includes the type and .equals doesn't. In this way records can still be proper j.u.Maps and = remains most useful for records (e.g. including type)."

Comment by Jason Wolfe [ 06/Jun/11 11:25 AM ]

On a related note:

http://dev.clojure.org/display/doc/Enhanced+Primitive+Support?focusedCommentId=1573146#comment-1573146

Regarding "hash maps and sets now use = for keys ... will use stricter .equals when calling through java.util interfaces":

Note that "=" is actually stricter than ".equals" for record types currently, because it includes type information.

This has important consequences for how (and whether) hash maps and sets actually obey the java.util interfaces.

For instance, if

(defrecord P []), ...

what should (.get {(P.) 1 (Q.) 2} (Q.)) return? How about if we .get an element of a third type (R.)?

In a similar vein, this behavior seems confusing at best:

user=> (java.util.HashMap. {(P.) 1 (Q.) 2})
#<HashMap {user.P@0=2}>

Comment by Aaron Bedra [ 28/Jun/11 6:36 PM ]

Open question:

  • the phrase "type-independent" is confusing. It is intended to talk about concrete numeric and collection types, but I can see why it gets confusing with records. Need an idea for two different terms here (and define them someplace). If somebody has one, please add it to this ticket.

Non-issues:

  • = and .equals are not and will not be the same. The whole point is to avoid Java's broken semantics (=) while providing an interop formula for those who need it (.equals)
  • Any types can collide as hash keys.
Comment by Aaron Bedra [ 19/Aug/11 11:34 AM ]

Any thoughts on the open questions part Rich?

Comment by Stuart Halloway [ 02/Sep/11 9:37 AM ]

I think the following is better:

monospaced
In addition, defrecord will define type-and-value-based =,
and will defined Java .hashCode and .equals consistent with the
contract for java.util.Map.
monospaced

But I don't want to hold release for discussion, so bumping this to approved backlog for further bikeshedding.

Comment by Stuart Halloway [ 02/Sep/11 9:39 AM ]

Better yet, let's just agreed on my prose and call this done.

Generated at Thu Sep 18 10:48:04 CDT 2014 using JIRA 4.4#649-r158309.