This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # architecture (3)
- # aws (4)
- # beginners (100)
- # boot (14)
- # cider (59)
- # cljs-dev (1)
- # cljsrn (24)
- # clojure (53)
- # clojure-dev (58)
- # clojure-italy (2)
- # clojure-spec (1)
- # clojure-uk (25)
- # clojurescript (7)
- # cryogen (1)
- # cursive (1)
- # datomic (9)
- # dirac (9)
- # duct (3)
- # off-topic (52)
- # om-next (3)
- # onyx (42)
- # portkey (28)
- # re-frame (3)
- # reagent (11)
- # rum (3)
- # shadow-cljs (12)
- # specter (7)
- # tools-deps (18)
- # vim (1)
- # yada (4)
If this is already documented/explained somewhere that you know of, I would appreciate a reference. Is there a straightforward reason why defrecord records are not clojure.core/= to maps with the same key/value pairs?
I guess meaning "a type with a name chosen by the defrecord creator, intended to be used explicitly by that name for later purposes, like which protocols it interacts with?" I'm not trying to be pedantic here, but may lapse that direction -- PersistentHashMap and PersistentArrayMap have a type in the JVM, too, but instances of those types with the same key/val pairs are = to each other. I know those type names are typically not intended to be cared about by most users of maps.
If you have two different defrecord's, but each with the same set of key/val pairs. Are they then equal per clojure.core/=? My own thoughts are, as the developer has given a defrecord a specific type that should infer meaning upon it.
with maps, the “java type” is not part of the comparison. with records, it is. This is (one of) the big features added by records - a named type.
My question was more rhetorical... two defrecords would not be considered equal, so logically a defrecord and map should not be as well.
in practice, I don’t know that I’ve ever run into this as an issue, and I’ve used defrecords a lot
@the2bears And my question could be applied just as well to two defrecord instances with different types, but same key/value pairs, being considered =. I'm not saying I think anything should change, just looking for the rationale.
Clojure goes out of its way to make things with different types clojure.core/= to each other, e.g. Java Integer/Long/BigInteger/Short/Byte with the same numeric values. Also lists/vectors/queues, both mutable and immutable.
Hmmm... for me with two defrecord instances it's more cut and dry. A developer has named them differently, typed differently, on purpose. They should not be treated as equal. But I can see your point re:the examples you listed.
It's conceivable a multimethod would treat them differently so then the "same" input would yield different results to the same function
Especially when the defrecord is converted to a map through removal of a declared key.
clojure.core/conj breaks a = b => f(a) = f(b) by design. I'm not saying the same rules should be applied to both, just that a=b => f(a)=f(b) is not a golden rule that Clojure claims to follow
Other functions f that do not follow that rule, I am pretty sure by design, not accident: meta seq occasionally hash
So I think the clearest rationale for defrecord is that by design, you use it when you want unique new types to be created, by name, and those names are important for taking advantage of the host's fast first-arg method dispatch capability for protocols, and because you want the ability for different types to be treated differently in those protocols (and also multimethods).
That pretty quickly leads to desiring them to be not clojure.core/= to each other.
I could be butchering all kinds of subtleties there, of course, but at least it gives me a bit of an "ah hah".
@dpsutton I wrote a couple of articles on deep dark corners of clojure.core/= and how it relates to hash consistency and the property a=b => f(a)=f(b), which I will link here in case you find anything further interesting there: Clojure equality: https://github.com/jafingerhut/thalia/blob/master/doc/other-topics/equality.md "Referential transparency", which I'm not sure any more that any two people use to mean the same thing when they say it, so the article is probably misnamed 🙂 https://github.com/jafingerhut/thalia/blob/master/doc/other-topics/referential-transparency.md
I have been revisiting and thinking about those articles again recently, and realized I had never mentioned defrecord behavior in the equality article. Looking to update those, so feel free to comment on anything you find wrong or confusing.
I’ve actually substantially rewritten your equality one with the goal to post it as a guide
Cool. I realize that the version I wrote perhaps doesn't exactly "accentuate the positive" but maybe focuses too much on the weird corners.
I was thinking of an audience who wants to know where all the potential land mines are 🙂
I guess you would prefer not to publish your incompletely edited rewrite of the equality article?
Oh, and related to Baker's egal operator, I read another paper recently where they called egal "always equal", versus something like Java's .equals being called "equals now". I liked the nice short names that seem to call out a critical difference.
And even the name "equals now" is really maybe only a good one in a single-threaded language, since multi-threaded turns that into "who knows?" 🙂
That paper is linked here, in case anyone is curious: http://lambda-the-ultimate.org/node/5509 The authors of the paper seem to be designing a programming language, and even given all of their knowledge of the issue, including Baker's egal, they seem to have chosen in their design something closer to Java's equals.
as clojure (and the egal paper building on common lisp) shows, you can add egal, but adding a way to check for pointer equality if you don't build one in seems like it would be impossible
I never even thought to consider that while learning Clojure and reading the egal paper, given that checking for pointer equality is kind of a built-in in just about any programming language I've ever learned. What caused you to think of that?