clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
nezaj 2021-01-13T02:45:07.141Z

Closing the loop on this. Was able to get it working! Thanks to a combo of • Heroku docs - https://devcenter.heroku.com/articles/debugging-clojure • ~1yr blog post updated for newer version of drawbridge: https://blog.jakubholy.net/nrepl-over-http-with-drwabridge-in-2020/ • This GH issue which was updated ~ 3 weeks ago repro-ing the issue with the latest lein but having it work in 2.9.3: https://github.com/nrepl/drawbridge/issues/40

❤️ 1
beders 2021-01-13T05:25:31.142600Z

hello there, fellow clojurians. I’m trying to find a tracing library where I can provide a fn to customize the trace output. More specifically I'd like to use tap>

beders 2021-01-13T05:26:29.143100Z

I looked at tools.trace but there doesn't seem to be a facility to get ahold of the output

dpsutton 2021-01-13T05:33:06.144800Z

i was looking at that the other day. seems like there should be a *trace-out* that is by default *out* but able to be rerouted. i think it directly uses *out*. Thus if there's any io in your code you get all or none. wouldn't necessarily solve your issue with tap but would give another way to redirect at least

seancorfield 2021-01-13T05:34:07.145500Z

Interestingly, it says of tracer "may be rebound to do anything you like" but it isn't marked dynamic so I guess... alter-var-root?

beders 2021-01-13T05:37:54.145800Z

thanks for the suggestions

dpsutton 2021-01-13T05:38:06.146100Z

i must be thinking of something else. its a different library. i thought it was tools.trace

seancorfield 2021-01-13T05:50:22.147100Z

@beders If you don't mind using alter-var-root to change clojure.tools.trace/tracer you can make it use tap>

seanc@DESKTOP-30ICA76:~/clojure$ clj -Sdeps '{:deps {org.clojure/tools.trace {:mvn/version "RELEASE"}}}'
Clojure 1.10.1
user=> (require '[clojure.tools.trace :refer :all])
nil
user=> (alter-var-root #'clojure.tools.trace/tracer (constantly (fn [name value] (tap> [:trace name value]))))
#object[user$eval409$fn__410 0x6411d3c8 "user$eval409$fn__410@6411d3c8"]
user=> (add-tap prn)
nil
user=> (trace (* 2 3))
6
user=> [:trace nil "6"]
(add-tap (fn [[k n v]] (when (= :trace k) (println "MY TRACE" n v))))
nil
user=> (trace (* 2 3))
6
[:trace nil "6"]
user=> MY TRACE nil 6

👍 2
beders 2021-01-13T05:50:48.147500Z

just fired up my repl to mess with it. Thanks a lot @seancorfield

seancorfield 2021-01-13T05:52:32.148Z

Now I know this, I might use tools.trace more since I use tap> very heavily 🙂

dpsutton 2021-01-13T06:16:34.148400Z

anyone know how to use the dotrace macro from tools.trace?

dpsutton 2021-01-13T06:18:15.149Z

i'd expect

(defn foo [x] (inc x))
(dotrace [foo] (foo 3))
to work but it gives an error about binding non-dynamic vars

dpsutton 2021-01-13T06:24:48.149300Z

is this a vestige of pre 1.3? > ;; As of Clojure 1.3, vars need to be explicitly marked as ^:dynamic in order for > ;; them to be dynamically rebindable:

seancorfield 2021-01-13T06:34:19.149700Z

I think that's the issue with tracer as well.

seancorfield 2021-01-13T06:34:37.150100Z

Time to open a JIRA or http://ask.clojure.org issue I think!

beders 2021-01-13T06:40:15.150800Z

looks like alter-varying trace-fn-call gives me more control over the output

seancorfield 2021-01-13T06:49:45.151500Z

@beders That won't help if you just want to trace an expression I think.

beders 2021-01-13T07:00:59.152900Z

true dat. I'm instrumenting whole namespaces, so I should be good. Thanks for the hint. trace unfortunately also assumes I want the to pr-str the value

2021-01-13T07:08:19.154600Z

What would people call the namespace prefix? Like if I have namespace com.foo.bar.core what would you call com.foo.bar, in Java it be called the package, but in Clojure?

seancorfield 2021-01-13T07:12:42.155100Z

I would call it the "stem" but I don't know whether that's common vernacular.

seancorfield 2021-01-13T07:13:04.155500Z

"parent" might be a reasonable designation?

seancorfield 2021-01-13T07:13:37.155900Z

(although namespaces are not really hierarchical)

2021-01-13T07:14:14.156200Z

I thought about calling it the ns-group?

2021-01-13T07:14:46.156700Z

meh, I guess it doesn't matter, I'll need a doc-string to explain anyways, don't think there's an intuitive name

2021-01-13T07:20:55.157800Z

it is tricky because in clojure they have no relationship, com.foo.bar.core is not "in" or a sub part of com.foo.bar

2021-01-13T07:21:33.158500Z

but because of the way namespaces are mapped to files and directories, on the filesystem there is a relationship

2021-01-13T07:23:45.159200Z

ns-group is definitely no good, because it implies a relationship that doesn't exist, it really isn't analogous to classes and packages in java

2021-01-13T17:17:24.178Z

In my case I'm building a scoping rule based on it. Something required in foo is accessible from foo.bar and foo.baz, etc. That's why I'm trying to come up with a name for it. But ya, like you said, it's not really a thing in Clojure, even though it kinda secretly is. I guess there's just no name. I went with ns-prefix since that felt most self-explanatory

Ramon Rios 2021-01-13T09:01:38.160700Z

Hi all. Does anyone here have some experience with chesire lib? Does someone have issues withUTF-8 while using parse-string ?

borkdude 2021-01-13T09:31:28.161700Z

@ramonp.rios should work

Ramon Rios 2021-01-13T09:33:57.161800Z

Something really bizarre is happening 😅 . I got the json into a string with the right utf-8 encode and after parse using parse-string, the strings at the map are not utf-8

borkdude 2021-01-13T09:35:28.162100Z

Maybe you can make a repro

Ramon Rios 2021-01-13T09:44:03.162300Z

Yes, working on it. Thanks

Ramon Rios 2021-01-13T10:19:56.162500Z

We found the issue. Actually it was a Yada misconfiguration 😅

Ramon Rios 2021-01-13T10:21:00.162700Z

I tried to repo in a separate project but it turns out it was working

Ramon Rios 2021-01-13T10:22:09.162900Z

I thought that was chesire on the beginning because we checked the issue right after the data pass througt the parse-string

Ramon Rios 2021-01-13T10:22:43.163100Z

So i went check with Yada and it was missing configuration to charset UTF-8

wasser 2021-01-13T14:20:04.166500Z

“Semantic qualifier” or just “qualifier” maybe? I know it sort of overloads “fully qualified” keywords, but I think they serve a similar semantic purpose.

kwladyka 2021-01-13T15:13:45.168500Z

There was a trick with var (`#'`) and ring to not reload ns with handler each time after change code anywhere. Something like this

(def handler
  (-> (bidi/make-handler route/route #'resources)
      (logs/ring-debug)
      (wrap-keyword-params {:parse-namespaces? true})
      (wrap-json-body {:keywords? true :bigdecimals? true})
      (wrap-params)
      (wrap-restful-format)
      (add-headers)
      (logs/wrap-exceptions)))
But for some reason it doesn’t work for me now. Do I use it correctly? How to fix this? Manually remember and reload this ns each time when I change anything is very irritating. PS I am not talking about alter-var-root. It should work as it is.

kwladyka 2021-01-13T15:24:33.168800Z

ok never mind, I had to add #' deeper in the code

2021-01-13T15:31:21.170800Z

hi, anyone still using overtone (or any clojure based music live coding)? it's been years... i wonder if someone still manage to run it on windows 10... i tried setting it up with supercollider the other day but no luck...

2021-01-13T16:00:19.170900Z

got the solution... https://github.com/overtone/overtone/issues/467#issuecomment-759545131

Dr. Moltu 2021-01-13T17:08:58.173200Z

Hi, i have a question, why i get clojure.lang.APersistentVector$SubVector type instead of PersistentVector in the following code? when I run the java code I get a PersistentVector :

IPersistentVector subvec = RT.subvec(
                PersistentVector.create(1, 2, 3, 4, 5),
                0,
                3
        );
        IPersistentVector vector = LazilyPersistentVector.create(subvec);
user=> (type (vec (subvec (vector 1 2 3 4 5) 0 3)))

2021-01-13T17:09:47.173800Z

Because vec doesn't coerce things that are already vectors into a different type

2021-01-13T17:10:25.174500Z

Probably as a performance optimization, since something that returns true for vector?, which a SubVector instance does, already is a vector.

2021-01-13T17:11:59.175100Z

Look at the (short) source code for the Clojure function vec to see the conditions it tests there, and the fast path where it returns the existing vector if it already is one.

Dr. Moltu 2021-01-13T17:13:30.175500Z

I'm looking at this

(defn vec
  "Creates a new vector containing the contents of coll. Java arrays
  will be aliased and should not be modified."
  {:added  "1.0"
   :static true}
  ([coll]
   (if (vector? coll)
     (if (instance? clojure.lang.IObj coll)
       (with-meta coll nil)
       (clojure.lang.LazilyPersistentVector/create coll))
     (clojure.lang.LazilyPersistentVector/create coll))))

2021-01-13T17:14:18.176400Z

In your Clojure expression (type (vec (subvec (vector 1 2 3 4 5) 0 3))), I believe that the code path executed within vec is the one that leads to returning (with-meta coll nil)

👍 1
💯 1
bronsa 2021-01-13T17:14:55.176900Z

you can force into a new instance by replacing vec with into []

👍 1
Dr. Moltu 2021-01-13T17:15:23.177500Z

ok I get it now thank you @andy.fingerhut @bronsa: )

alexmiller 2021-01-13T17:20:29.179500Z

vec guarantees that you get a vector in the return. it makes no assertions about whether that is the same or different vector from the input value.

🙌 1
2021-01-13T19:31:18.181300Z

Hey all, do you have any recommendations for something that can quickly bootstrap a *nix server for Clojure/Script apps? I'm looking to host a bunch of different apps, each of which should have its own server, but I don't want to go through the pain of setting one up from scratch each time. I'm thinking something like Docker? Or even a script? Any recommendations will be much appreciated 🙂

Alexis Vincent 2021-01-13T19:46:14.181600Z

Docker would be good

Alexis Vincent 2021-01-13T19:46:27.182100Z

makes it platform agnostic

2021-01-13T19:46:30.182300Z

nah

Alexis Vincent 2021-01-13T19:47:28.183900Z

Can run on a bare linux server, managed kubernetes, Google Cloud Run, anywhere really. And gives your the isolation you want

2021-01-13T19:48:31.184600Z

sure, and then hire 8-10 guys to run all that

2021-01-13T19:48:51.184900Z

and maybe a manager or two for them

2021-01-13T19:49:44.185400Z

if you build uberjars, java -jar whatever.jar is a great way to deploy and run stuff

2021-01-13T19:50:44.186700Z

I would even start off with a single repo and building a single uber jar and just run java -cp uberjar.jar clojure.main -m some.clojure.namespace to launch the different servers

Alexis Vincent 2021-01-13T19:51:20.187600Z

@hiredman Respectfully, I think perhaps you haven’t seen what modern managed container offerings can do for you.

Alexis Vincent 2021-01-13T19:52:15.188900Z

I’m not recommending @andyfry01 stands up and manages a kubernetes cluster.

2021-01-13T19:52:53.189700Z

it is also trivially simple to go from an uberjar to a docker container should you choose to

2021-01-13T19:53:43.190400Z

like, saying "use docker" doesn't actually answer questions about how to build and run apps, it just moves those questions into a container

Alexis Vincent 2021-01-13T19:55:27.192200Z

OP’s question was “any recommendations for something that can quickly bootstrap a *nix server for Clojure/Script apps? I’m looking to host a bunch of different apps, each of which should have its own server, but I don’t want to go through the pain of setting one up from scratch each time.”

2021-01-13T19:55:42.192500Z

I am aware of managed container offerings, and have spent time (I won't call it wasted) getting them working. they do a lot of stuff, but to pretend they don't drag along a lot of complexity you can likely avoid if you are just starting is to be willfully blind

2021-01-13T19:56:07.192800Z

perhaps I misread

2021-01-13T19:56:15.193300Z

I took "server" to mean "service"

2021-01-13T19:56:30.193700Z

not literally devoting a machine vm or otherwise to each

Alexis Vincent 2021-01-13T19:57:09.193900Z

:man-shrugging:

2021-01-13T19:58:15.195500Z

I guess what I'm looking for is something where I can define a single "standard" server configuration, and then use that to configure multiple separate servers

Alexis Vincent 2021-01-13T19:58:38.196200Z

For simple use cases I would say, throw the jar into a container and deploy to google cloud run with minimum instance count of 1.

2021-01-13T19:58:52.197Z

All of these servers will be running different apps, but they'll share a lot of stuff in common (like mongodb for instance), so I just want something to get the basics configured right away

Alexis Vincent 2021-01-13T19:58:58.197300Z

gcloud run deploy --image http://gcr.io/cloudrun/hello --min-instances=1 helloservice

2021-01-13T19:59:10.197800Z

I think most people use something like ansible or chef for that kind of thing, which isn't really on topic for #clojure

Alexis Vincent 2021-01-13T19:59:38.198300Z

replace http://gcr.io/cloudrun/hello with your container image and your have what you need.

Alexis Vincent 2021-01-13T20:01:00.198900Z

without the 8-10 + 2 team @hiredman suggests.

2021-01-13T20:01:16.199100Z

Haha, not yet anyway 😛

2021-01-13T20:01:19.199300Z

Thanks guys, appreciate it!

Alexis Vincent 2021-01-13T20:02:03.200100Z

🙂 Although @hiredman is right, this is off topic for #clojure

marrs 2021-01-13T20:25:42.207400Z

Hi all, I'm trying to find a way to rerun a unit test from within my repl using [clojure.tools.namespace.repl/refresh. Running something like (do (refresh) (test-var (var my-ns/my-test))) yields a correct result every time I update and rerun the test, but if I try to put that code behind a function (e.g. (defn r [] (refresh) (test-var (var my-ns/my-test)))), it only binds the test the first time it is run. Subsequent calls to (r) yield the original result. Anyone know what's going on there?

seancorfield 2021-01-13T20:37:04.208Z

(yet another reason not to use "refresh"-based workflows perhaps?)

marrs 2021-01-13T20:45:15.212600Z

If the alternative is :reload-all then I'll stick with refresh. I'd actually like to get to the bottom of what's going on, because I don't see what would cause the two examples to behave differently

caumond 2021-01-13T20:46:07.213500Z

@seancorfield how do you do in case of namespace refactoring so. I dont feel confortable with refresh ( lot of special cases) but dont know to do in another way.

seancorfield 2021-01-13T20:47:24.213900Z

@caumond Can you elaborate on what you mean by "namespace refactoring"?

2021-01-13T20:48:41.215300Z

Use resolve instead of the var special form

2021-01-13T20:49:41.216900Z

Your function is holding on to an interned var that has been removed by refresh, you need to re-reolve it everytime

caumond 2021-01-13T20:51:11.218600Z

I have cases when I want to re organize name space. So copy paste function and recompile function is easy. But I always have doubts, did I update all functions using the older ones.

seancorfield 2021-01-13T21:04:18.224300Z

@caumond Using consistent aliases for namespaces helps a lot there (and linters like clj-kondo can help "enforce" that) so a function reference is always foo/bar everywhere (except uses in its own ns). You can also unmap the old function from the old ns by way of clean up. Generally, if I'm moving a public function from one ns to another, it tends to have a bunch of small private functions that it is implemented by, so as a "shortcut" I will sometimes remove-ns and then load-file on the old ns to clean things up a bit more -- for me that's ctrl-; r ctrl-; f -- and I always eval each top-level form as I change it anyway, and if I'm pasting multiple functions into a new ns I'll save and reload that ns: ctrl-s ctrl-; f. Moving functions around is one of the few cases where I will save/load rather than just eval'ing forms (and leaving files "dirty" -- unsaved).

🤘 1
seancorfield 2021-01-13T21:05:26.225200Z

I do have require .. :reload-all bound to a hot key (`ctrl-; R`) but almost never need to use that. And I don't use any sort of ns "refresh" ever in my workflow.

caumond 2021-01-13T21:09:58.225400Z

I ll try this. Seems reasonably simple and efficient.

kwladyka 2021-01-13T21:47:25.227500Z

(let [root-logger (.getLogger (LogManager/getLogManager) "")]
    (.setLevel root-logger Level/ALL)
    (doseq [handler (.getHandlers root-logger)]
      (.setLevel root-logger Level/ALL)))
(l/debug "foo")
I don’t see debug logs. Why? .setLevel works for all levels expect ALL / FINEST / FINER / FINE, but if I will set thing to Level/WARNING it works correctly and not show info. I will set this to Level/INFO it shows info. But it doesn’t work for lower level. What I miss?

marrs 2021-01-13T21:47:32.227600Z

thx @hiredman. Just saw this message. That worked a treat

kwladyka 2021-01-13T21:51:01.229200Z

As I understand this it is actually JUL issue, not Clojure but still I don’t know why this is happening.

kwladyka 2021-01-13T21:51:17.229600Z

Because

(let [root-logger (.getLogger (LogManager/getLogManager) "")]
    (.setLevel root-logger Level/ALL)
    (doseq [handler (.getHandlers root-logger)]
      (.setLevel root-logger Level/ALL))

    (.fine root-logger "fine"))
doesn’t work too

2021-01-13T21:55:18.229900Z

I would try calling .getLoggerNames on the log manager, and then iterating over each logger name and getting the logger for that name, then each handler for that logger, then setting the level on each handler

2021-01-13T21:56:32.230100Z

I realize this doesn’t actually answer the question, but if I might suggest a lateral solution: I gave up on Java’s baroque logging system long ago. Now I use https://github.com/ptaoussanis/timbre

2021-01-13T21:57:08.230400Z

I just went through something like this with log4j2 which is not going to match jul, but it took a lot of iterating over a lot of things to set the level everywhere, and what you have to do is fairly sensitive to the logging config file if you have one

kwladyka 2021-01-13T21:58:05.230600Z

Thanks @paul.legato but I did timbre -> clojure.tools.logging. Long story why but this is right thing 🙂

kwladyka 2021-01-13T21:58:43.230800Z

@hiredman what is strange it works for INFO and up, but not below this level

kwladyka 2021-01-13T21:58:59.231Z

and I do iteration on handlers, all examples show only this

kwladyka 2021-01-13T21:59:06.231200Z

but for sure I miss something

seancorfield 2021-01-13T21:59:29.231400Z

The main thing is to try to get to the place where you have absolutely the minimum possible compilable change between each "eval" -- or turned around, that you always "eval" as often as you possibly can while making changes. Tightening that loop is what's key for a good REPL-based workflow.

2021-01-13T22:00:22.231600Z

what does l/debug do?

kwladyka 2021-01-13T22:01:01.231800Z

“nothing”

(l/debug "foo")
=> nil

2021-01-13T22:01:16.232Z

ok, I mean, what is the definition of l/debug

kwladyka 2021-01-13T22:01:18.232200Z

(let [root-logger (.getLogger (LogManager/getLogManager) "")]
    (.setLevel root-logger Level/ALL)
    (doseq [handler (.getHandlers root-logger)]
      (.setLevel root-logger Level/ALL))

    (.fine root-logger "fine"))
even this doesn’t work, but it does for .info

kwladyka 2021-01-13T22:01:50.232400Z

so for sure it is the issue about JUL itself, not clojure.tools.logging

2021-01-13T22:12:23.233700Z

(do
  (doseq [ln (enumeration-seq (.getLoggerNames (java.util.logging.LogManager/getLogManager)))
          :let [logger (.getLogger (java.util.logging.LogManager/getLogManager) ln)]
          handler (.getHandlers logger)]
    (.setLevel logger java.util.logging.Level/ALL)
    (.setLevel handler java.util.logging.Level/ALL))
  (.fine
   (.getLogger (java.util.logging.LogManager/getLogManager) "")
   "fine"))
should work

2021-01-13T22:12:46.233900Z

what I see locally is there is a logger called "" and a logger called "global"

2021-01-13T22:13:11.234100Z

don't ask me why some levels and not other get logged or whatever

kwladyka 2021-01-13T22:18:14.234300Z

thank you. I am still not sure why it works, but I will figure out this soon. I mean I am trying very similar things now and it doesn’t work. Interesting.

2021-01-13T22:20:58.234600Z

another thing is logger creation is stateful (I am sort of conflating log4j2 with jul here), so when you create a new logger (which tools.logging does whenever you execute a logging statement in a namespace that has had a logger created for it yet) it is initialized in someway (I don't entirely understand) to match the setting of the root logger, but then later if you change the settings of the root logger, it won't change the settings of that namespace logger

2021-01-13T22:22:20.234800Z

so in order to correctly configure everything you have to be careful of the order things are run in

caumond 2021-01-13T22:32:06.235Z

Yes. I succeed to do that for small changes. More challenging for big ones. But im on the way. Thx

kwladyka 2021-01-13T22:37:28.235200Z

sh** I had a big “typo”

(let [root-logger (.getLogger (LogManager/getLogManager) "")]
    (.setLevel root-logger Level/ALL)

    (doseq [handler (.getHandlers root-logger)]
      (.setLevel handler Level/ALL))

    (.fine root-logger "fine"))
Before I was doing (.setLevel root-logger Level/ALL) twice (also for handlers…)

kwladyka 2021-01-13T22:37:37.235400Z

You save my day

kwladyka 2021-01-13T22:37:43.235600Z

❤️

2021-01-13T23:29:08.236600Z

is there a way to hack an already existing protocol to set :extend-via-metadata to true ?

ghadi 2021-01-13T23:30:56.237700Z

record scratch hold up. what are you really trying to achieve?

ghadi 2021-01-13T23:32:43.239200Z

(The hidden assumption here is that you don't own this protocol, otherwise you would simply edit your source file.)

2021-01-13T23:35:52.241200Z

Nothing that's a good idea, just had a thought to use maps as core.async channels (the maps have inner channels and metadata). I suppose I could flip this and just extend IMeta to channels (which I know also isn't a good idea, this is more of a thought experiment)

ghadi 2021-01-13T23:44:54.245200Z

when I've needed to associate channels with extra information, I have either used channels as a lookup key in a map {ch {...info about ch}} (when the chans are all known to a particular controller) or flow some info that includes the channel {:some :event :in ch} (which you can send... over a channel)

2021-01-13T23:48:43.247200Z

the best way to associate a channel with extra data is to just enrich the data coming out of it with that data: e.g. wrap the channel (defn wrap [ch data] (async/go [data (async/<! ch)]))

2021-01-13T23:49:53.248500Z

channels are not values so you'll need to extend the identity metadata stuff, which will cause you call kinds of problems if you are using timeouts (similar with sticking channels in maps or sets)

ghadi 2021-01-13T23:51:44.250500Z

I would have a hard time reading code that used map+channel hybrids, though it is technically possible to make non-channels participate in channel protocols

2021-01-13T23:52:20.251100Z

wrapping timeouts is very nice because you can get a nice bit of data back (this is a timeout for this connection or whatever) instead of just nil when the timeout expires

2021-01-13T23:52:46.251500Z

gotcha yeah all that makes sense, thanks! I think the wrapping will work well

ghadi 2021-01-13T23:53:10.251700Z

I want

2021-01-13T23:54:34.251900Z

wrap is cool, but checkout withNack http://cml.cs.uchicago.edu/pages/cml.html