clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
Gleb Posobin 2020-12-30T06:07:28.085Z

@sdmoralesma What do you mean from now on? After discovering that clojure.set includes some relational algebra, or has something happened recently?

pez 2020-12-30T11:19:43.092300Z

Help a tool smith, please. What is a good workflow for navigating namespaces that a tool like Calva could support? Calva encourages working from “inside” the source code files themselves, but many people are still using the repl window as well. Observing how people try to navigate namespaces most of them dive straight down the “How things can go wrong” path mentioned here: https://clojure.org/guides/repl/navigating_namespaces#_how_things_can_go_wrong Experimenting a bit with it I find that I can probably add a command to Calva to load the current namespace even though it has been created (by evaluating the code in the file). That would “encourage” this “wrong” path though, I think… Maybe that doesn’t matter as long as it gets the work done?

vemv 2020-12-30T11:34:06.092400Z

I think it's quite common to have the IDE able to run a specific "reload" command (like tools.namespace's refresh, a given app's custom reset, etc) under a keyboard shortcut So, as a IDE user I just hit the keyboard shortcut whenever my code is ready. That doesn't preclude using the repl, or even evaluating a form from the file (that's a favorite of mine; as it's a hybrid approach) When I visit a new file that wasn't required before, my emacs does just (in-ns 'that-ns) but does not attempt to automagically load its code That's my responsibility, be it via the keyboard-bound refresh, or various repl/eval interactions

vemv 2020-12-30T11:34:45.092600Z

That would seem a sensible approach to me as it's minimalistic/transparent and doesn't impose any specific workflow

p-himik 2020-12-30T11:37:51.092800Z

Cursive can "load file in REPL", whatever that means. Interestingly, it seems to also load all the dependencies:

;; hgs/xxx.clj
(ns <http://hgs.xxx|hgs.xxx>)

(def a 1)

;; hgs/yyy.clj
(ns hgs.yyy
  (:require [<http://hgs.xxx|hgs.xxx>]))

(println "Hello" <http://hgs.xxx/a|hgs.xxx/a>)

;; REPL
(ns <http://hgs.xxx|hgs.xxx>)
=&gt; nil
(require '<http://hgs.xxx|hgs.xxx>)
=&gt; nil
a 
Syntax error compiling at (/tmp/form-init16785379888913250927.clj:1:350).
Unable to resolve symbol: a in this context
;; I executed the "Load file in REPL" command on hgs/yyy.clj here
Loading src/hgs/xxx.clj... done
Loading src/hgs/yyy.clj... 
Hello 1
Loaded

pez 2020-12-30T11:50:56.093500Z

Thanks. Sounds like I can go ahead with my idea for having a command that loads the current namespace then, from both your answers. In my spike it looks quite exactly like that Cursive workflow.

👍 1
pez 2020-12-30T11:56:35.093700Z

Like so.

👍 1
pez 2020-12-30T11:57:30.094200Z

At line 27 there I issued the command. If that is not clear from the screenshot.

p-himik 2020-12-30T11:57:48.094500Z

Will it also load all the dependencies in the same way?

pez 2020-12-30T11:58:38.094700Z

It evaluates all the code in the file, so its requires will get loaded. If that is what you mean.

p-himik 2020-12-30T12:00:31.094900Z

Not really - in my example above, the dependency is also evaluated, not just loaded. If I understand it correctly, otherwise evaluating yyy.clj would not create <http://hgs.xxx/a|hgs.xxx/a> because the namespace <http://hgs.xxx|hgs.xxx> already exists.

vemv 2020-12-30T12:02:00.095100Z

what happens if both namespaces define a? That specific feature seems more delicate

pez 2020-12-30T12:02:42.095300Z

I think that will work as in your example. Let me try…

p-himik 2020-12-30T12:03:24.095500Z

@vemv It would be ns1/a and ns2/a - no issue here. The REPL has only one namespace as currently active.

👀 1
pez 2020-12-30T12:18:19.095800Z

With file contents similar to your example @p-himik

pez 2020-12-30T12:21:00.096200Z

Note that the load file in repl command already exists in Calva. So loading the pez.yyy namespace can be done from the file. What’s new in my spike here is that I can do it from the repl prompt. Not sure if that is what the Cursive example showed.

p-himik 2020-12-30T12:22:55.096400Z

It's not the same. Note that in my example I execute what would be (ns <http://pez.xxx|pez.xxx>) in your case, not (ns pez.yyy).

pez 2020-12-30T12:29:47.096600Z

Hmmm, that actually exposes an issue in current Calva. If I do (ns '<http://pez.xxx|pez.xxx>) before loading pez.yyy I run into the problem I posted in the thread start. I guess that is quite uncommon in practice, but anyway.

p-himik 2020-12-30T12:39:31.097Z

A probably more common workflow that would suffer from the same issue: 1. Evaluate xxx.clj in REPL 2. Make some changes in xxx.clj 3. Start using those changes in yyy.clj (so yyy depends on xxx) 4. Load yyy.clj in REPL 5. Receive an error

p-himik 2020-12-30T12:41:47.097200Z

Also, I have no idea if Calva handles it but in Cursive I regularly suffer from the situation described here: https://nelsonmorris.net/2015/05/18/reloaded-protocol-and-no-implementation-of-method.html Is it possible for Calva to automatically reload relevant namespaces to avoid that error?

p-himik 2020-12-30T12:42:43.097400Z

I know that it's not really about the initial topic but it seems quite relevant given that it's also about loading files and their dependencies.

pez 2020-12-30T12:43:21.097600Z

I filed an issue on Calva now, please ensure that I have understood the problem correctly and let me know if I haven’t: https://github.com/BetterThanTomorrow/calva/issues/907

p-himik 2020-12-30T12:43:52.097900Z

LGTM, thanks!

pez 2020-12-30T12:44:10.098100Z

What happens in step 3 in the workflow you describe there?

p-himik 2020-12-30T12:44:27.098300Z

By "start using" I meant just writing new code.

pez 2020-12-30T12:45:09.098500Z

So that should work in Calva w/o error, but now I am a bit more on the defence here so must try before confirming. 😃

p-himik 2020-12-30T12:46:32.098700Z

Please do tell how it turns out. :)

pez 2020-12-30T12:47:59.098900Z

You were right with your step 5 unfortunately . 😃

p-himik 2020-12-30T12:49:20.099100Z

At least the reason is known, so this confirmation just increases the priority, I guess.

pez 2020-12-30T12:49:21.099300Z

But in this case I can reload <http://pez.xxx|pez.xxx> and things start to work. I think I do this more or less on auto-pilot.

p-himik 2020-12-30T12:49:34.099500Z

Right.

p-himik 2020-12-30T12:50:00.099700Z

But it would also work in the original workflow outlined in that issue #907.

pez 2020-12-30T12:50:14.099900Z

I can probably get out of the mess in the reported issue by reloading <http://pez.xxx|pez.xxx>… yeah, you beat me to it.

😄 1
pez 2020-12-30T12:54:01.100300Z

So, fixing #907 should fix this too, I think. And fixing #907 would mean to help the user with loading the files in order. I wonder if the current command Calva has for refreshing namespaces actually does that… must check.

pez 2020-12-30T12:56:13.100500Z

Nope. Hmmm…

pez 2020-12-30T12:59:22.100700Z

Now to your other question there. I’m pretty sure, given #907, that this will be the same problem in Calva. Will try it now to see for myself.

👍 1
pez 2020-12-30T13:09:47.101300Z

So, Calva doesn’t offer any help with this currently. How would you like it to be supported?

p-himik 2020-12-30T13:20:39.101500Z

No idea as of now - I started evaluating Calva just a couple of days ago (IntelliJ IDEA pisses me off more and more with each release). I guess it should be as non-intrusive as possible. I.e. in the article that I linked, z.core should be reloaded automatically as well. But the user has to be notified about it in an obvious way, ideally with a reason describing why z.core was reloaded at all.

pez 2020-12-30T13:24:39.101700Z

I am reluctant to make Calva load things automatically. It would certainly “help” with many common support questions we get, but I really think the user must be in charge of what is being loaded, and when.

p-himik 2020-12-30T13:25:43.101900Z

Without doing it automatically, how would you fix 907?

pez 2020-12-30T13:25:56.102100Z

But a command for reloading all files that depend on a given namespace.

p-himik 2020-12-30T13:26:52.102300Z

With such a command, would it be possible for a user to make it automatic via configuration?

pez 2020-12-30T13:27:25.102500Z

I hear you about 907, but I see it as that the command is named Load Current File and Dependencies it sort of promises something it doesn’t keep.

pez 2020-12-30T13:28:18.102700Z

So, a setting where Calva always loads dependent namespaces on Save, you mean?

pez 2020-12-30T13:28:53.102900Z

I don’t think I can do it on mere re-evaluation…

p-himik 2020-12-30T13:29:51.103100Z

> reloading all files that depend on a given namespace It wouldn't be necessary. I think only the files that use the protocols and other similar entities would need to be reloaded. > it sort of promises something it doesn’t keep Not sure I follow. If you do load everything, what is the promise that's not kept? > So, a setting where Calva always loads dependent namespaces on Save, you mean? It may be a setting. Ideally, it would be something that's scriptable. Sorry, I have no idea yet whether it's at all doable but AFAIK you can write CLJS code to extend Calva and/or VSCode (a huge advantage compared to IDEA+Cursive).

pez 2020-12-30T13:32:34.103300Z

About 907. Given that the dependency <http://pez.xxx|pez.xxx> is not loaded by the command, (if the namespace has been created), I see that as a bug.

pez 2020-12-30T13:34:24.103500Z

If we can target the reload to protocols, and similar, then I might be persuaded to make it an automatic thing, but I haven’t thought it through yet.

pez 2020-12-30T13:36:58.103700Z

My question regarding Save was that that would be enough automatic. The way my workflow is leaves me quite often with a lot of unsaved files, because I mostly just evaluate my programs to existence. 😃

pez 2020-12-30T13:39:33.103900Z

There is currently a setting where Calva evaluates the file on Save. So if we introduce a command that dependent files be re-evaluated, then the auto-setting for that would be in the same spirit.

p-himik 2020-12-30T13:59:04.104100Z

Ah, I think I misunderstood one thing - I wouldn't want for anything to happen automatically on Save. I also prefer to issue the command to reload stuff manually. By "automating" I meant automatically reloading every file that needs to be reloaded to keep the app working when a user manually reloads one file.

pez 2020-12-30T14:48:57.106Z

Ah, then we're on the same page. Once a command behaves in a predictable manner I'm all for automatic. 😎

🤝 1
2020-12-30T19:00:12.107600Z

What Cursive does is, if you reload file X, and it depends on file Y, and you changed file Y but did not reload file Y, when you reload file X, Cursive will also reload file Y

2020-12-30T19:04:38.108Z

Which avoids a lot of the "what can go wrong"

2020-12-30T19:05:33.108200Z

Also, I think it's great that you can run the command from the repl as well, so it's more like reload namespace

2020-12-30T19:08:23.108400Z

Cider also has something similar: cider-ns-refresh will reload all modified files

p-himik 2020-12-30T19:09:52.108600Z

It's not only about the modified files. It's also about namespaces that have been created but were not populated properly. Although as pez said, this use case is probably quite rare.

2020-12-30T19:11:27.108800Z

What do you mean by not populated properly?

2020-12-30T19:11:46.109Z

That you forgot to load the rest of the namespace code? Or that loading threw an exception?

p-himik 2020-12-30T19:12:58.109200Z

I meant executing (ns xxx) in a REPL, like described in examples above.

2020-12-30T19:15:01.109400Z

Oh, so you switch the reply namespace manually by executing (ns xxx) and then try to call a function in that namespace, but it doesn't exist because you actually never loaded the corresponding file?

p-himik 2020-12-30T19:15:45.109600Z

No, it's not about one namespace. Have you checked the examples above?

2020-12-30T19:16:35.109800Z

Ok, I was looking at the prior example, I see now.

2020-12-30T19:18:26.110100Z

So you mean, it be better to have it load all dependencies, not just modified ones?

p-himik 2020-12-30T19:20:10.110300Z

I think so. Although I'm not sure how that would work in a workflow with global state atoms or something like that.

2020-12-30T19:22:02.110500Z

State is always the downsides to these "auto-sync" like features.

p-himik 2020-12-30T19:23:30.110800Z

Right. So should be fine as long as users know what they're doing and the consequences of their actions.

2020-12-30T19:25:14.111Z

Ya, but changing namespace in the repl is pretty rare no?

2020-12-30T19:26:48.111300Z

Also, I do think Cursive has both Load and Load All no?, And the latter would reload all

p-himik 2020-12-30T19:28:36.111500Z

Above, we have agreed on this, yes. My "although" above is about the whole "reload files that were not directly reloaded by the user" thing. Regardless of the reasons for their reloading. I don't see "Load All" in the list of REPL actions in Cursive.

2020-12-30T19:36:51.113400Z

I was wondering, tools.namespace also unloads, but what if it didn't? Wouldn't that solve most of the caveats it has, at the expense of you could miss the fact one function calls something that no longer exists.

2020-12-30T19:38:36.114100Z

@didibus you'd need some kind of manual override if you changed a defmulti though, for example

2020-12-30T19:41:36.114200Z

True, I could get in the habit of having a (def my-multi nil) above them

2020-12-30T19:42:06.114400Z

But I'm also wondering here, maybe tools.namespace could be smarter and unmap defmultis but not the rest?

2020-12-30T19:43:47.114700Z

I also wouldn't be too bothered if when I changed a defmulti I still needed to manually deal with it

2020-12-30T19:44:07.114900Z

Are there other cases like this? Apart from defmulti?

2020-12-30T19:45:34.115100Z

Hum, I might have been mistaken. Haven't used Cursive in a while

2020-12-30T19:47:47.115300Z

So in Cider, you have: refresh and refresh all, which run the tools.namespace refresh and refresh-all. Both of those should work in the example given. You also have reload and reload-all. Those are based on require :reload and require :reload-all respectively. I think both of those would also work.

2020-12-30T19:48:56.115600Z

And finally you have Load buffer, which is just like sending all the code in the buffer to be evaled. That one would not work, since it won't force reload a lib that is already loaded.

Reily Siegel 2020-12-30T21:46:55.122Z

Is it possible to force Clojure to resolve import statements at compile time? Currently import statements produce bytecode that looks like

class_ = ((Namespace)RT.CURRENT_NS.deref()).importClass(RT.classForNameNonLoading((String)"a.java.class"));
I need to be able to run the resulting AOT'd clojure code through a java remapper (obfuscator), which does not seem to work when the imports are resolved in this way. Upon further inspection, this only happens in clojure_ns$loading___xxxx___auto__xxx.class. In all other instances, the import statement is resolved correctly and is properly converted by the remapper.

Reily Siegel 2020-12-30T21:50:51.122100Z

You could write

(def a-fn (memoize (fn [x]
                    (println x))))

2020-12-30T23:36:21.123Z

Whoops sorry, I misspoke. My problem is memoizing no responding to recursive calls - only the outer call. Any idea?

2020-12-30T23:38:11.123200Z

Sorry, I figured it out…thx