Defrecord and = docstring clarifications (regarding record equality)

85 views
Skip to first unread message

Jason Wolfe

unread,
Jan 31, 2011, 11:33:39 PM1/31/11
to Clojure
I just ran into the following surprise:

user> (defrecord P [])
user.P
user> (defrecord Q [])
user.Q
user> (= (P.) (Q.))
false
user> (.equals (P.) (Q.))
true

This is not a bug (but I do find it confusing -- I did not expect (P.)
and (Q.) to collide as map keys):
http://groups.google.com/group/clojure/browse_frm/thread/7ba5215d59f2f177

However, the docstring of defrecord says it "will define type-and-
value-based equality and hashCode". Perhaps this could be
clarified?

Along the same lines, the docstring of = says "same as Java
x.equals(y), 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.

Thanks, Jason



Ken Wesson

unread,
Jan 31, 2011, 11:43:17 PM1/31/11
to clo...@googlegroups.com
On Mon, Jan 31, 2011 at 11:33 PM, Jason Wolfe <ja...@w01fe.com> wrote:
> I just ran into the following surprise:
>
> user> (defrecord P [])
> user.P
> user> (defrecord Q [])
> user.Q
> user> (= (P.) (Q.))
> false
> user> (.equals (P.) (Q.))
> true
>
> This is not a bug (but I do find it confusing -- I did not expect (P.)
> and (Q.) to collide as map keys):
> http://groups.google.com/group/clojure/browse_frm/thread/7ba5215d59f2f177
>
> However, the docstring of defrecord says it "will define type-and-
> value-based equality and hashCode".   Perhaps this could be
> clarified?

It seems clear enough to me that type is a factor in equality.

The real bug here is that .equals returns true in this case.

> Along the same lines, the docstring of = says "same as Java
> x.equals(y), 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.

There is where clarification is needed, namely that records are not
"collections" for this purpose.

Alternatively, records could have an enforced mapping {:type
TheRecordsClass} that does not actually take up storage space, but
appears when records are queried and automatically imposes the desired
equality semantics if records were simply treated as maps -- other
than that a plain map with the same type key-value pair could now
compare equal to the record. (Would that be a bad thing though?)

Jason Wolfe

unread,
Feb 10, 2011, 2:07:55 PM2/10/11
to Clojure

> Alternatively, records could have an enforced mapping {:type
> TheRecordsClass} that does not actually take up storage space, but
> appears when records are queried and automatically imposes the desired
> equality semantics if records were simply treated as maps -- other
> than that a plain map with the same type key-value pair could now
> compare equal to the record. (Would that be a bad thing though?)

That might be the clearest way to allow records to behave as Java
Maps, while preserving type-based equality. It's how I did things
manually to keep struct-maps straight, before there were records.

The more I think about the current behavior, the less I think I like
it. If P and Q have different implementations of the same protocol,
you can have (.equals (P.) (Q.)) but completely different semantics
for (foo (P.)) and (foo (Q.)).

In any case, I've posted a ticket for the docstring fix:
http://dev.clojure.org/jira/browse/CLJ-736

Reply all
Reply to author
Forward
0 new messages