Fork me on GitHub
#clojure
<
2023-06-26
>
vemv11:06:00

Besides from CIDER which uses https://github.com/vspinu/sesman to manage its nrepl connections, are there other editors that allow multiple connections to the same project, for the same platform, and same port? e.g. CIDER allows you to create two JVM nREPL connections to port 54321. But does one typically want that? What are some good use cases for such multiple connections/repls?

mkvlr12:06:36

iirc prepl was designed so you’d have multiple connections open for different use cases, i.e. a separate connection for completions

flowthing18:06:34

Tutkain doesn’t use prepl, but does open (by default) two connections to each Clojure runtime; one for evals, one for everything else. Additionally, it technically allows you to open as many connections (these eval connection plus tooling connection pairs, really) as you want to a single runtime, but I don’t see much of a reason to do that, really.

Ken Allen14:06:44

Is there a replacement for clojure.tools.cli.api/tree for the new non-alpha tools.deps? I've been using that to help figure out where vulnerabilties are coming from in whitesource scans. Looks like I can put something together using clojure.tools.deps.treebut would be nice if something already existed 😛

Alex Miller (Clojure team)15:06:37

the stuff in ctd.tree is the replacement. you might also want to look at how -X:deps tree works as it puts all of that together. See: https://github.com/clojure/tools.deps.cli/blob/main/src/main/clojure/clojure/tools/deps/cli/api.clj#L80-L125

Alex Miller (Clojure team)15:06:46

if you have follow up questions, best in #C6QH853H8

Ken Allen17:06:08

just plain old -X:deps tree does the job, somehow I missed that. Thanks

Kelvin16:06:03

Does this not work?

& {:keys [wildcard-append? wildcard-limit]
   :or {wildcard-append? true
        wildcard-limit   (when wildcard-append? 1)}}
;; => wildcard-limit is always 1
I’m trying to do a “dynamic default” where wildcard-limit is 1 if wildcard-append? is true, nil otherwise

p-himik16:06:03

Even if it works, don't do it. You're relying on a specific order of things inside {...}, which isn't a great thing.

Kelvin16:06:18

You’re just talking about destructuring right? (as there isn’t a problem with evaluating expressions inside regular maps)

Kelvin16:06:04

So is my idea of a “dynamic default” that you can easily see in a docstring just a bad idea?

p-himik16:06:27

Just use a plain let. Everybody knows it, everybody does it that way. If it's important to document, add it explicitly to the docstring. Alternatively, if you don't use wildcard-limit if wildcard-append? is not true, just set its default to 1 unconditionally.

2
Noah Bogart21:06:20

is it possible to run clojure -M:some-alias args for a given project (deps.edn plus directory of source code) but from another directory?

Alexander Kouznetsov22:06:49

Hey, just wanted to cross-post since I’ve got no comments in the original channel.

2
Alex Miller (Clojure team)22:06:53

it would be helpful if you shared a full example and what output you get

phronmophobic22:06:49

Another thing to consider is that the ^Baz syntax is a https://clojure.org/reference/metadata#_metadata_reader_macrosand happens at read-time which is before the macro has a chance to make any changes. It might be the problem is with your test is written rather than your macro. An example that demonstrates your issue would be helpful.

Alexander Kouznetsov22:06:42

The output I’m getting is "cannot resolve class for baz (tagged as Baz)" Nevermind, that’s the error message from my code.

phronmophobic22:06:08

An example would helpful. My guess is that Baz isn't imported in the namespace where the test is defined.

Alexander Kouznetsov22:06:23

And I think what macro does is (-?> tag symbol resolve).

Alexander Kouznetsov22:06:08

It is actually defined in the test namespace. But when I was debugging it further, resolve relies on *ns* which was set to user when test is running outside of repl.

Alexander Kouznetsov22:06:31

I guess the simplest fix is to wrap with binding [*ns* ...]

Alexander Kouznetsov22:06:50

And the test works when executed in repl

phronmophobic22:06:37

maybe, but I wouldn't expect that your macro should be in charge of resolving

(defmacro my-macro [form]
  form)

(meta (macroexpand '(my-macro ^Memory {})))
;; {:tag Memory}

(meta (my-macro ^Memory {}))
;; {:tag com.sun.jna.Memory}

{:tag Memory}
;; {:tag com.sun.jna.Memory}

phronmophobic22:06:56

I think resolving the symbol, Memory , to the class com.sun.jna.Memory typically happens after the macro returns a result (ie. during evaluation)

phronmophobic22:06:37

The difference between (meta (macroexpand '(my-macro ^Memory {}))) and (meta (my-macro ^Memory {})) is that the former's result is before evaluation and the latter's is after evaluation.

Alexander Kouznetsov22:06:54

I think this example captures everything I have. I apologize for the error message above, it was from my code. resolve returns nil and even macroexpand fails to resolve the macro name properly when run non in repl. If I don’t use n-test/m and do just m, macroexpand doesn’t resolve it and leaves as is.

Testing n-test
nil nil

FAIL in (m-test) (n_test.clj:21)
expected: (= n_test.A (macroexpand (quote (n-test/m (A. 5)))))
  actual: (not (= n_test.A nil))

Alexander Kouznetsov22:06:41

Example output if not using a fully qualified name for m:

Testing n-test
(m (A. 5)) clojure.lang.PersistentList

FAIL in (m-test) (n_test.clj:21)
expected: (= n_test.A (macroexpand (quote (m (A. 5)))))
  actual: (not (= n_test.A (m (A. 5))))

phronmophobic22:06:36

You can read my other responses for the explanation, but your macro shouldn't be calling resolve in this case. If you did want to try and test using macroexpand, then you should test for the symbol, 'A and not the class n_test.A.

Alexander Kouznetsov23:06:12

I agree that resolve doesn’t work in test runner. But it perfectly works everywhere else where the macro is used.

Alexander Kouznetsov23:06:25

It’s been in the codebase for ages 🙂

Alexander Kouznetsov23:06:16

Without resolve, it is just a symbol A that doesn’t carry any meaning that macro tries to extract from it. It wants to get access to the record class it represents in a given context.

phronmophobic23:06:34

Generally, macros don't have access to runtime info and only see the code as raw data literals. Given your example, I don't see why ^A needs to be resolved.

Alexander Kouznetsov23:06:46

But they need to be able to recognize symbols and generate code based on what those symbols represent.

phronmophobic23:06:39

An example would be helpful, but usually, resolving A to my.class.A happens at evaluation time after the macro runs.

phronmophobic23:06:49

If you do need access to runtime info, then usually the macro generates the code that will run at runtime to use the runtime info.

Alexander Kouznetsov23:06:07

I agree that it is an option but that defeats the purpose of this particular macro which tries to perform evaluation time checks (such as that the field exist on a record) and generate efficient code (such as accessing the field using the java interop.

phronmophobic23:06:49

That makes sense.

phronmophobic23:06:25

It sounds like your macro is correct. Maybe try using quasi quote in your test:

(macroexpand `(n-test/m ^A (A. 5)))

phronmophobic23:06:52

It kinda depends on what you're trying to test.

Alexander Kouznetsov01:06:49

Oh, cool, it does work for this example. I’ll try it for the original problem. Thanks a lot for the suggestion!

Alexander Kouznetsov01:06:07

Yep, that works there too! Thank you very much!

🎉 2