Fork me on GitHub

Surprising behavior:

(get-in [1] nil)
;;=> [1]

R.A. Porter00:01:01

I agree it's unexpected, but it is referenced on the doc page -


Thanks! I expected nil, so I’ll use it like so: (and ks (get-in blah ks)

👍 1

Here’s another interesting one: keep uses actual nil as opposed to filterand remove which are based on logical truth:

(keep #(when-let [p (peek %)] (and (odd? p) (inc p)))
                                        [[1] [2]])
;;=> (2 false)


keep says non-nil in its docstring


filter and remove say logical true and false in their docstrings


@hiredman indeed, that’s what I meant.


keep uses actual nil (or non-nil) as the fn’s return to decide, as opposed to logical truth for the others. Somewhat unexpected.


But it makes sense nevertheless, as it’s used to aggregate transformed values rather than just weeding them out unchanged.


I see in the core.async code base, the use of (^:once fn* [] [email protected]) in a macro, I read a bit about it, they say it has something to do with locals clearing, but I didn't really get it. Is there a reason to have the macro to this? Like performance?


It allows for clearing references to closed over values so they can be gc'ed


When a function closes over some value it is kept in a field on a fn object


Which means it cannot be garbage collected, and it lives as long as the fn object does, because the fn object could be called multiple times, and could need that closed over value every time


:once is a promise that you will only ever call the fn once


So useful in macros that expand to a fn literal, that immediately pass the literal to some implementation function that will only ever call it once


Do you have to use fn* for that? Or could you annotate :once on fn as well?


I am not sure, but I would be surprised if the fn macro preserved that metadata


So likely you need fn*


There are macros in clojure.core that use it as well, like lazy-seq


Hum, ok, but I'm a bit confused. So I guess in normal usage its not meant that you'd rely on this?


In the case of core.async/thread like what's the benefit?


lazy-seq make a bit more sense to me, to not have the sequence continue to have all closed values in memory


lazy-seq and thread are both using fn* for the same thing


To capture some code and execute it in a different context (at a different time or on a different thread)


They aren't making a general function intended to be invoked more than once


Ok, thanks, I need to think it through a bit, but I have the info I need to do so


On another note, does anyone know of a Clojure doc generator that lets you write the doc for a function in markdown or something like that separate from the code? I want to generate something a bit like this: See how its like a API reference, but each function has a really long form description, with examples, and all that. So I don't want to write all that in a doc-string, seems like to much.


@didibus both and next.jdbc rely on that ^:once fn* stuff, FYI.


fn doesn't preserve ^:once , you have to use fn*


here's an example of how it works:

user=> (def x (let [a (Object.)] (^:once fn* [] a)))
user=> (x)
#object[java.lang.Object 0x466d49f0 "[email protected]"]
user=> (x)


There doesn’t seem to be a transducer version of partition-all with a step 😞. Is there some kind of clever workaround to get the equivalent functionality within a transducer?


xforms has that


Found it 👍. Thanks!


Does anyone know of a good source of documentation for how to keep resources in your jar? Should they always be at <group>/<dep>/filename rather than just resources/filename in case a dependency also has resources/filename and you are at the mercy of the classloader which one you actually see? Wanting to convert my iffy knowledge into well-founded understanding.

Alex Miller (Clojure team)16:01:45

yes, you should assume you are playing in a global space that could be inhabited by any other libs files

Alex Miller (Clojure team)16:01:17

so you should prefix sufficiently to avoid conflicts (as you do with code)


thanks @alexmiller. I knew that was lurking, but wasn’t sure if it only applied to lib jars vs uber jars, etc.


Just for clarity are you saying use something like com.github.mycompany/foo/resources/filename or what does that <group>/<dep> look like as an example?

Alex Miller (Clojure team)16:01:22

it needs to be sufficiently unique - what exactly that means will depend on the context :)


for me i’ll just use resources/metabase/metabase/common-passwords.txt rather than resources/common-passwords.txt

👍 2

(i find the reverse dns stuff distasteful and overly verbose most of the time)


Yeah the reasoning was explained to me at some point but it does irk my aesthetics/elegance censor

Joshua Suskalo16:01:10

Yeah, sufficiently unique is probably fine to be at the root level if you're building an application and not a library. If you're building a library then it should be done in such a way as to not conflict with other libraries (or root level stuff made by an application using your library).

💯 2

What is the state of openapiv3 support in clojure these days? It still looks like neither reitit nor martian support it yet… :thinking_face: Juxt’s jinx looks nice but obviously only takes care of the json schema side of things; and looks to be behind by two draft specs…


is there a way to do lein repl and enter the repl command => (start)in a single command (in the background of the shell)? I’m trying to create an environment in the ci where I can run the frontend tests, and need to start a server in it


lein repl <<< "(println 42)" runs the given input and then exits Guess you can have a loop for keeping a server


Maybe I can use lein runbut how do I run lein run in the background?

Joshua Suskalo18:01:11

although you'd have to make sure that your CI tool will kill that process eventually


running lein run & locally gives:

[2]  + suspended (tty input)  lein run


and after doing lein run &, lein run still connects to port 3000 which it shouldn’t if lein run & is working correctly in the background

Joshua Suskalo18:01:15

Hmm, that's odd


lein is a build tool


use it to build a deployment artifact, and run that without lein


@rickmoynihan we backlogged reitit + openapi3 to “next”, need it in a project. First impl on malli, but schema & spec support JSON Schema, so should follow soon.


oh amazing! Is there anywhere we can track the progress? An issue in malli or branch/PR, or just the reitit issue ( )? I’m also curious what you’re referring to by: > schema & spec support JSON Schema, so should follow soon.


e.g. lein uberjar and java -jar whatever.jar &


actually lein run < /dev/null seems to work

Lucio Assis18:01:26

What was that website again where you gave it input data + expected output data and it told you what clojure fn could get you from A to B?


that’s borkdude’s re-find i believe

Lucio Assis18:01:12

The very one, thank you

Joshua Suskalo18:01:24

I see that this isn't the full core.logic search, it can't figure out a composition of functions

Joshua Suskalo18:01:32

that's pretty cool though


Is there a API call to rewind to the top, without loosing the zipper? z/root causes a NPE like so:

(-> [1 2 3 4] vector-zip down root down)
I would rather not have to call up the chain and constantly check along the way…Thanks for any comment.


I could always hold onto the original 🙂


But then I would lose the changes


(-> [1 2 3 4] z/vector-zip z/down z/root z/vector-zip z/down) root says it returns the root node , reflecting any changes. So just grab that node and get a zipper view of it again?


@dpsutton Thanks! I should have thought of that 🙂


lein run < /dev/null & && npm i
doesn’t seem to work? I’m trying to run the first command in the background and then run another command?


using && after & is incoherent - && means "run this if the previous step succeeded", and & backgrounds a process ignoring success / failure / completion state as mentioned above, lein is a build tool not a process runner


get “zsh: parse error near `&&’”


I am trying out on a project and I keep getting -T is no longer supported, use -A with repl, -M for main, or -X for exec Clojure version 1.10.3 is specified in the project. Clojure CLI version is:

clj --version
Clojure CLI version
I have tried both {:git/tag "v0.6.6" :git/sha "4d41c26"} and {:git/tag "v0.7.5" :git/sha "34727f7"} for the dep from working repositories. I am on an M1 Mac.

Joshua Suskalo18:01:11

that deprecation notice is from old versions of the cli. You should see if you can update your cli version.


It works for someone running on an older version Clojure CLI version But I will check out updating.

Joshua Suskalo18:01:57 is newer than


oh you right haha


nvm. Late night coding lol

Joshua Suskalo18:01:32

The cli uses a version scheme of <CLOJURE_VERSION>.<COMMITS>

👍 2
Joshua Suskalo18:01:07

so the last element is a monotonically increasing value that can be used to compare versions of the CLI, even ignoring the clojure version.


ah I see. Yea that makes more sense.


What's the go-to library for in memory caching in Clojure? I looked into core.cache but it seems single threaded?


If it's JVM based check caffeine


@ggfpc12495 Could you elaborate on that comment? It relies on Clojure's atoms which are fine for multi-threading...


(we use core.cache at work heavily in a multi-threaded environment)


@seancorfield I completely missed that point facepalm


Thanks! I'm trying to decide between that and caffeine


Happy to answer Qs about core.cache (since I'm the maintainer these days).


I've been curious about the status of ? What would be needed to merge it in?


I wanted @U050WRF8X to take a look at it and sanity check the composability of it with other caches.


And it's a lot of code to be added in a patch and I really haven't had the time to really dig into it and verify all of it (there are a few coding quirks in there I'll need to sort out when I'm ready to merge it in).


Yeah, that makes sense. For me, the patch would be helpful but it's far from critical. I appreciate taking it slowly and safely