Fork me on GitHub
#clojure
<
2021-07-28
>
jumar05:07:38

I saw somewhere that *ns* isn't bound during AOT compilation but I'm wondering if that's true. In particular, def's docstring says: > Creates and interns a global var with the name > of symbol in the current namespace (*ns*) or locates such a var if So I guess it must be set? The compiler seems to be setting *ns* here: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L7696 (called here: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Compiler.java#L7875) My use case is that I want to automatically define vars based on their "definitions" in a hashmap instead of manually calling def. I wanted to use (intern *ns* ... for that purpose Something like:

(def config-keys {:key1 {} :key2 {}})
(defn- intern-config-var [[config-key _]]
  (intern *ns*
          (symbol (name config-key))
          (read-env config-key)))
(run! intern-config-var config-keys)
which should produce vars key1, key2, etc.

seancorfield05:07:39

A common trick is to have (def my-ns *ns*) at the top of the namespace and then use my-ns subsequently.

seancorfield05:07:56

That way my-ns is defined to be the actual namespace (at load/compile time) rather than whatever *ns* is bound to at run time.

jumar05:07:33

So given that I'm calling this immediately (the last line) as a top-level form there shouldn't be any difference, right? When would this be a problem? If intern-config-var was public and called from another ns?

hiredman06:07:49

*ns* is always set during compilation

hiredman06:07:18

The tricky thing is compilation and runtime are interleaved in such a way that people often expect *ns* to have the same value at runtime as it has at compile time, which is basically only the case in the repl

hiredman06:07:15

Your use case is likely fine

👍 3
vemv06:07:49

Maybe not clojure-specific, but anyone has a clever trick for caching Maven dependencies that will survive unrelated changes to project.clj / deps.edn?

vemv06:07:16

mmm, I had forgotten about this https://grep.app/search?q=fallback%20to%20using%20the%20latest%20cache%20if%20no%20exact%20match%20is%20found that's the answer. I think I had worked for a while on projects not featuring that snippet

hiredman06:07:14

Tying the maven cache to the sha of the dependencies seems silly. You should share the same m2 everywhere for every build as much as possible

thumbnail08:07:46

With a high churn in dependencies the cache will be indefinitely growing though. I encountered problems with this in a js project a while back. Restoring the cache took more time than downloading the dependencies at some point. The workaround was including a timestamp in the cache-key.

tessocog12:07:13

how can i turn a org.httpkit.BytesInputStream into edn?

delaguardo12:07:57

(clojure.edn/read ( <org.httpkit.BytesInputStream>))

tessocog12:07:19

no doesn't work

tessocog12:07:35

class java.io.BufferedReader cannot be cast to class java.io.PushbackReader (java.io.BufferedReader and java.io.PushbackReader are in module java.base of loader 'bootstrap')

jaju13:07:49

One more level of wrapping might help. PushbackReader constructor instantiates from a Reader - a quick scan of the class shows.

tessocog12:07:24

clojure.edn/read expects a pushbackreader

tessocog13:07:34

#(java.io.PushbackReader.
     (
      (java.io.PushbackInputStream.
       %)))
seems to be it

jaju13:07:28

While this works - do you need the inner-most PushbackInputStream? I think the reader can take the httpkit object - which I believe extends InputStream

3
Jim Newton13:07:59

the documentation of cl-format claims that it is fully compatible with the CL version of format. However, in CL the ~A directive (print aesthetically) pretty-prints the corresponding argument. For example (format out "~A" some-list) outputs the same as (pprint some-list out) However in clojure (cl-format out "~A" some-list) outputs the contents of some-list all on a single line. Does anyone know whether it is possible to make this work correctly? I've seen the dynamic variable *print-pretty* which seems to have no effect on ~A

Jim Newton13:07:24

if not, is there a way to tell the default format to print the corresponding argument as if by pprint ?

Jim Newton13:07:23

according to line 1338 of cl_format.clj it seems ~A dispatches to print-str rather than to some form of pprint-to-str .. I suspect that is a bug, because I don't see any comment there explaining how the pretty-printer is intended to be triggered here.

Jim Newton14:07:24

It seems like it should use something like (fn [data] (with-out-str (pprint data)) rather than print-str

p-himik14:07:35

At this point, it seems like making a post on https://ask.clojure.org/ would be worth it.

tessocog14:07:28

i want to add user keybindings to my emacs config for reloading/starting/stopping my integrant system. cider does not seem to expose any non-interactive functions for evaluating a clojure form. I want an emacs script that finds the system ns and evaluates the start/stop methods. how do i do this?

tessocog14:07:54

in other words, i want to be able to do all the cider interactive stuff non-interactively (programmatically in elisp)

Derek14:07:32

I know some people make use of cider-refresh-before-fn and cider-refresh-after-fn

Derek14:07:05

Set that in .dir-locals.el and you can ‘hook’ into cider-refresh to stop and start your system

Daniel Ziltener14:07:29

Is there an up-to-date core.cache adapter for Redis? I tried https://github.com/strongh/crache, but that doesn't work with the current Clojure version anymore

vemv15:07:03

TIL about the lib :) last commit isn't too distant so I think the right thing in this case is opening an issue with a repro

Daniel Ziltener15:07:57

I ended up fixing the namespace, updating the dependencies, and opening a pull request 🙂

vemv15:07:19

kudos 🚀

roklenarcic15:07:17

I’ve got a namespace with this var declaration:

(def yy protocols/ApiAuth)
I start REPL which loads this namespace. I do absolutely no reloads of any kind. And yet:
(identical? yy protocols/ApiAuth)
=> false
how is this possible

Alex Miller (Clojure team)15:07:56

what does protocols/ApiAuth eval to? I'm assuming a protocol?

roklenarcic15:07:57

I’ve been running into a bit of trouble with protocols lately, and I know that I need to have a clean target folder and if I reload the namespace with the protocol I need to reload all the namespaces with protocol implementations, but this one has been baffling. When I start REPL about a 100 namespaces get loaded due to being included from the core one. It seems that same protocol gets defined multiple times which is odd

Alex Miller (Clojure team)16:07:49

protocols are just maps, so you could compare them with clojure.data/diff to find things that are different. I'm guessing the :on key (the interface class) is different

roklenarcic16:07:47

oddly:

(identical? (:on yy) (:on protocols/ApiAuth))
=> true
(identical? yy protocols/ApiAuth)
=> false

Alex Miller (Clojure team)16:07:17

well, it was just a guess. you can use clojure.data/diff to narrow it down

Alex Miller (Clojure team)16:07:50

I mean, the protocol gets updated as it gets extended, so you might be seeing an older version vs a newer version with different extensions

roklenarcic16:07:14

ah… maybe that’s the problem with my code

roklenarcic16:07:20

(s/def ::auth-token (partial satisfies? protocols/ApiAuth))

Alex Miller (Clojure team)16:07:24

when you def yy, you're just getting a point in time, not tracking updates

roklenarcic16:07:28

that spec fails for objects it shouldn’t fail for

roklenarcic16:07:50

I am guess it closes over a version of protocol without the necessary implementations in the map

Alex Miller (Clojure team)16:07:57

maybe? you might be better with using an anonymous function there instead so you're not evaluating early

Alex Miller (Clojure team)16:07:26

#(satisfies? protocols/ApiAuth %)

roklenarcic16:07:43

yeah that works as expected

lassemaatta16:07:44

Yeah, I recently encountered the same thing, using an anonymous function fixed it

roklenarcic16:07:03

well this is definitely a gotcha for most people

lassemaatta16:07:27

I think https://clojure.atlassian.net/browse/CLJ-2094 describes the same scenario, would you agree @U66G3SGP5?

lassemaatta16:07:21

(https://clojure.atlassian.net/browse/CLJ-1814 also relates, but from a performance point of view I guess)

roklenarcic16:07:09

it’s not a problem that it works that way, but it’s definitely unexpected by most

roklenarcic18:07:22

I think partial behaviour is not poorly described. What is surprising is that extending a protocol produces a new value…. in most languages type identifiers are immutable singletons and as most people grok protocols as some sort of type/interface abstraction, they get blindsided by this “type” identifier changing as new implementations are defined.

Alex Miller (Clojure team)18:07:41

I think that's a good insight. There are two "stateful" runtime constructs in Clojure - protocols and multimethods. As Clojurists we should not be surprised that state creates problems (like temporal coupling)

Alex Miller (Clojure team)18:07:02

but you can't have open dispatch systems without managing state over time to allow for late behavior extension

Alex Miller (Clojure team)18:07:57

I do think it is not immediately obvious what the tradeoff is in partial vs anon fn wrt evaluation and closures and that probably warrants a faq entry

lassemaatta03:07:24

yeah, I guess there are two different things here (which may or may not be obvious depending on your level of expertise): a) why (partial foo bar) isn't the same as a similar anonymous function (I'd guess this also applies to other HoF's too, like comp) and b) the value of a protocol may change when it's extended

lassemaatta03:07:34

I remember encountering the a) issue when adding instrumentation to a function foo, but had already defined some helpers with partial e.g. (def helper (partial foo 1)) -> calling helper with some incorrect args wouldn't trigger an instrumentation failure

Alex Miller (Clojure team)16:07:11

(identical? (:on yy) (:on protocols/ApiAuth))

Adie17:07:37

Hi , I am sending this data in body in a put api

[{"topic":"xyz", "key":"abc", "message": "pqr"}]
I need to parse these params at handler one by one. Can someone suggest the cleanest way to do it?

dpsutton17:07:40

build=> (require '[clojure.data.json :as json])
nil
build=> (json/read-str "[{\"topic\":\"xyz\", \"key\":\"abc\", \"message\": \"pqr\"}]")
[{"topic" "xyz", "key" "abc", "message" "pqr"}]

Adie17:07:48

Not as json string. but the parameters

Adie17:07:17

(defn myFunc
      [{:keys [params]}]
              (let [
                    topic (:topic params)
                    key (:key params)
                    message (:message params)
                    ])
)
Need to add the for loop to this

dpsutton17:07:28

params usually isn't a vector like you posted above

dpsutton17:07:57

but you could try [{{:strs [topic key message]} :params]

dpsutton17:07:19

(defn foo [{{:strs [topic key message]} :params}]
  [topic key message])

(foo {:params {"topic" "t" "key" "k" "message" "msg"}})
#_-> ["t" "k" "msg"]

Adie17:07:23

[ {"topic":"xyz", "key":"abc", "message": "pqr"}, {"topic":"xyz1", "key":"abc1", "message": "pqr1"}, {"topic":"xyz2", "key":"abc2", "message": "pqr2"}] ] Would it run for this one?

dpsutton17:07:48

that's a different shape. what do you want your function to do?

dpsutton17:07:12

generally, figure out how to make a function that takes one map with topic, key, and message, and then figure out how to do it multiple times

👍 3
Adie17:07:25

This is the json body in my api request. Need to parse this data one at a time

dpsutton17:07:51

ok. i'm not aware of any json libraries that will parse one entry at a time

dpsutton17:07:03

but i suspect you mean you need to act one one "record" at a time, not parse one at a time

3
dpsutton17:07:39

you just need to parse the json string? Or do you mean something else?

winsome19:07:06

How do I write a tab literal character?