Fork me on GitHub
#clojurescript
<
2023-09-22
>
Andrea Ambu16:09:40

I've run into some issues with defrecord during interactive development. When reloading my file the defrecord runs twice and all previous instances won't hash/equal to equal new instances, so things disappear from maps and all sort of issues you can imagine. Here's an example:

(defrecord Pos [col line])
(def mypos (->Pos 3 4))
(defrecord Pos [col line])
(def mypos2 (->Pos 3 4))
(= mypos mypos2)
false
=>(= mypos mypos)
true
This also happen when I run clj on version 1.11.1 locally but doesn't happen on http://tryclojure.org Is this working as intended?

p-himik16:09:46

Yes, a known issue with redefining records and other things to which you might hold a reference somewhere.

Andrea Ambu16:09:41

so they are just bad to use with a repl and browser hot-reload or is there some other technique a-la defonce?

p-himik16:09:20

With hot code reload in a browser it should work just fine. At least, AFAICT it has always been working for me. The technique that I prefer on the CLJ side is to never reload things by hand. Instead, I rely on the "reloaded" workflow where I make a set of changes, send a specific keystroke, and my REPL reloads all the necessary namespaces while tracking all of the dependencies. For that, I use clojure.tools.namespace.repl and Integrant (helps with stateful things, and there are alternatives).

Andrea Ambu16:09:53

I came across this using hot-reload with re-frame/shadowcljs. Saving the ns with defrecord makes all the keys in app-db useless

p-himik16:09:48

All the keys? That sounds bizarre given that usually the keys there are keywords or other scalars.

Andrea Ambu16:09:12

all the keys of that type

p-himik16:09:25

Hmm. Yeah, I have never seen that probably only because I almost never use records. But sounds logical. Code references should get refreshed by hot code reload, but data references cannot be when that data is in defonce, just like re-frame.db/app-db.

👍 1
Matthew Davidson (kingmob)06:02:25

Came across this old thread, and thought I'd chime in. This technique won't work if you change an actual record's definition, but Potemkin's defrecord+ (and related macros) are designed for exactly this. They skip re-evaluation if the defrecord's body is unchanged. Dunno about cljs tho.

p-himik07:02:00

Yeah, that's only for CLJ. And not necessary with a reloaded workflow. ;) With CLJS, I would simply avoid storing records altogether.

Matthew Davidson (kingmob)07:02:34

"Doctor, it hurts when I do that." "Then stop doing that...forever." laughcry

p-himik10:02:49

Well... yeah. :) Of course, sometimes it does make more sense to use a record instead of a map. But it's a relatively rare case. And most of the time you can still find a way to use plain maps without sacrificing anything.