Fork me on GitHub
#polylith
<
2022-04-08
>
Hukka11:04:35

During my challenge of making our code work with repl driven workflow, I found an odd problem where having functions named identically with core functions stops new versions from appearing in calling function, when crossing namespace boundaries. At first I though this is related deftypes, then to polylith's way of linkin deps.edns together, but it does actually appear with just one simple deps.edn https://github.com/hukka/repl-driven-bug-repro

Hukka11:04:17

So if I have a function repro2/read or named anything else than read, but still a core function, another function repro/func-b does not "see" a new version of it, if I just eval (defn read) in its namespace. But if I re-eval func-b's definition, not just the buffer, it works

Hukka11:04:35

I've yet to determine if this could be a bug in nrepl or cider-nrepl, since that's the setup I have

Hukka11:04:09

During this cascade of problems I also learned that if I redefine a type with (deftype MyType), the helper function ->MyType will keep using the old version. Also a bummer for repl driven flow.

Hukka11:04:39

At this point this doesn't have much to do with polylith except the discussion here about refreshing namespaces vs just evaling things in the editor, but I don't really know where to go from this point 😕

Hukka11:04:42

Sure, that helps/works

Hukka11:04:47

Though still so that you need to run it after every change; it doesn't have similar effect to evaling the (defn func-b) separately

Hukka11:04:11

Ah, a friend commented that he can reproduce this without any files, just on command line, so it's not a nrepl problem

seancorfield17:04:23

(I would strongly recommend not using c.t.n.r/refresh -- it is not needed and just adds complexity and fragility to your workflow)

seancorfield17:04:31

@U8ZQ1J1RR I can't reproduce this. I started a plain Socket REPL -- no nREPL/CIDER stuff -- and in my editor I can "load file" on repro.clj and when I eval (func-b) I get the initial output; then I open repro2.clj and modify the read function and eval that top-level form into the REPL (I don't need to save the file here); then switch back to repro.clj and eval (func-b) and it shows the modified output as expected.

seancorfield17:04:25

That is exactly what I would expect: I can re-eval a top-level form (a defn in this case) and when I call it via eval'ing code in another namespace, the new definition is invoked.

Hukka17:04:36

Yeah, that's how it should work

Hukka17:04:08

Does the pure clj version work for you too, the one where there are no files?

seancorfield17:04:38

Yes, if you correctly use (in-ns 'repro2) and (in-ns 'repro) to switch to existing namespaces -- instead of using (ns repro2) and (ns repro) which will overwrite things.

seancorfield17:04:21

(! 707)-> clj
Clojure 1.11.1
(ns repro2)

(defn read []
   (prn "Called repro2/read 1"))

(defn read2 []
   (prn "Called repro2/read2 1"))

(ns repro
  (:require [repro2]))

(defn func-b []
  (prn "Called func-b: 1")
  (repro2/read)
  (repro2/read2))

(func-b)
nil
repro2=> repro2=> WARNING: read already refers to: #'clojure.core/read in namespace: repro2, being replaced by: #'repro2/read
#'repro2/read
repro2=> repro2=> #'repro2/read2
repro2=> repro2=> nil
repro=> repro=> #'repro/func-b
repro=> repro=> "Called func-b: 1"
"Called repro2/read 1"
"Called repro2/read2 1"
nil
repro=> (in-ns 'repro2)
#object[clojure.lang.Namespace 0x43b0ade "repro2"]
(defn read []
   (prn "Called repro2/read 2"))

#'repro2/read
(defn read2 []
   (prn "Called repro2/read2 2"))
#'repro2/read2
repro2=> (in-ns 'repro)
#object[clojure.lang.Namespace 0x7b60c3e "repro"]
repro=> (func-b)
"Called func-b: 1"
"Called repro2/read 2"
"Called repro2/read2 2"
nil
repro=> 
(the prompts disappear when pasting multi-line code into the REPL so it makes it a bit harder to follow)

Hukka17:04:29

I also notice that you are running 1.11.1. I've been holding off for a while to see if any other surprises are found, but I should try repro with that too.

Hukka17:04:17

I think there's a socket repl client for neovim, so I could try that as well

seancorfield17:04:00

The Clojure version is unimportant for this situation.

seancorfield17:04:18

(we've been running 1.11 alpha/beta/rc builds in production for a long time)

Hukka17:04:52

Ok, I'll look into the socket repl then

Hukka18:04:32

The socket repl client for vim is clunky, it can only eval files, not forms. But I can still get the problem reproduced by using that to reload the repro2 file and running (in-ns 'repro) (func-b) straight in the cli repl

Hukka18:04:22

What editor are you using? And if relevant, what plugins?

Hukka18:04:01

And to clarify, indeed using in-ns fixes the pure clj "version", it's now just editors that I can't get working

seancorfield18:04:07

I use VS Code and Clover (for the Socket REPL; and Calva for all the static stuff).

seancorfield18:04:20

I haven't used nREPL for many, many years at this point.