Fork me on GitHub

I have a couple questions about the package cache with tools.deps: • Is there a way I could copy a cache folder to allow for building on another machine without internet access? • Are package caches per-machine or per-project? Is there a way to re-use the same package cache for several projects (if that's not already the case by default)?


I've done some experimentation and it seems I can at least partially answer myself: The cache folder for maven packages does not change, it's always $HOME/.m2 (the default for maven). There is also .cpcache folder, which I assume is for other kinds of deps (git?) but I was mostly interested in mvn dependencies.


with tools.deps there are two conceptual entities: deps cache and artifacts. Deps cache is per-project cache of computed classpaths. Artifacts stored separately: normal maven jars - in globally configured maven repository, git-based deps in $HOME/.gitlibs


.cpcache doesn't cache the deps themselves, just the computed classpaths that point to the local cache of the deps (in m2 etc.)


it speeds up startup by allowing reuse of the classpath instead of computing it if the deps have not changed


Hi, in Clojure, are transducers (`eduction/sequence`) also chunked? Looking at the source, it seems yes, but double checking.


eduction & sequence sequences (i.e. when used as a seq ) are not chunked.

👍 4

Hello, I am reading this article About danger of default reader. What is the best way to do the opposite thing - serialize data structures into a string?


depends on what you want exactly, @feikas


I guess pr-str is what I want, but asking just in case if this one also is safe.


what do you mean by safe?


there is also *print-dup* that allows producing "unsafe-to-read" forms:

(binding [*print-dup* true] 
  (pr-str [String #'clojure.core/inc]))
"[#=java.lang.String #=(var clojure.core/inc)]"


So, lazy-seqs... How do I treat them correctly? I thought map is lazy. But calling map on a lazy-seq puts me into an infinite loop it seems...


No doall or anything alike. Just using seq? to see if it is a sequence, then map, and the caller calls take 3 on the result.

Ivan Koz11:01:24

well because printing will try to "realize" resulting sequence


I don't call print anywhere though. Just using the result of (take 3 (function-that-maps lazy-seq-thing)) in a test


A few lines up, (take 3 lazy-seq-thing) works perfectly as expected

Ivan Koz11:01:29

what's your function

Ivan Koz11:01:16

(take 3 (map (partial * 2) (iterate inc 0)))
=> (0 2 4)


(defn mainblock-inputs-gen [{:keys [input url] :as state} parse-fn & {:keys [fetch-fn]}]
    (and (nil? input) (or (keyword? url) (string? url)))
    [(mainblock-url-fetching parse-fn url state)]

    (and (nil? input) (or (coll? url) (seq? url)))
    (map #(mainblock-url-fetching parse-fn % state) url)

    (string? input)
    [(parse-fn input)]

    (coll? input)

with url being the lazy sequence.


...and input being nil in this example of course.


If url is a lazy seq of lazy seqs of lazy seqs ad infinitum, it will be an endless recursion.


Oh, disregard that - I read mainblock-url-fetching as mainblock-inputs-gen.

Ivan Koz12:01:23

yeah unless map is being realized it shouldnt evaluate


Are you sure that's the infinite loop though and not just mainblock-url-fetching never returning?


Or maybe parse-fn.


Yes, in the test, I've set mainblock-url-fetching to (fn [parse-fn url _] (parse-fn url)) and parse-fn to identity

Ivan Koz12:01:06

so you basically calling identity on entire url lazy-seq?


Well, I just tested it with url being (range) and just called (take 3 ...) on it. It works perfectly, no infinite loops.


user=> (take 3 (mainblock-inputs-gen {:url (range)} identity))
(0 1 2)


No, identity gets called inside the mainblock-url-fetching which gets called inside the map

Ivan Koz12:01:12

looks like it's not your map, but rather you trying to put mainblock-url-fetching into a vector


And yes, when I use (iterate inc 1) as a lazy seq instead, it works...

Ivan Koz12:01:28

so mainblock-url-fetching is effectively (identity url) according to your description


Must be your url generation then. Can you (take 3 url) without halting?


@p-himik yes, I can, that's what I do in a test that runs right before this one

Ivan Koz12:01:56

now replace [(mainblock-url-fetching parse-fn url state)] by (mainblock-url-fetching parse-fn url state)

Ivan Koz12:01:12

and call take 3 on result of mainblock-inputs-gen


@nxtk What would that solve? In that block, url is a scalar.


Hmmm I think I found the problem... The function generating the lazy sequence returns a map containing the lazy seq, not the lazy seq directly...

Ivan Koz12:01:05

@p-himik oh i guess you are right


is there a way to include a local jar file with tools deps?

Alex Miller (Clojure team)13:01:48

Yes, use a coordinate like {:local/root “/path/to.jar”}


Thanks! 👍 I thought this only worked with other projects using deps.edn


Hello guys, anyone messed around with ? I installed confluent CLI and start the repl. then loaded the pipe example

user=> (ns pipe)
pipe=> (confluent/start)
Syntax error compiling at (/private/var/folders/zz/zyxvpxvq6csfxvn_n0000000000000/T/form-init10224179169549008804.clj:1:1).
No such namespace: confluent
What do I miss?


There's actually a separate #jackdaw channel that some of the FundingCircle guys lurk in - they're good at responding too.


this is a regression in the example, I'm going to see if I can find the correct namespace in the edit history of that ns


OK - the example never worked, I'll ping the author


I'm certain the confluent in the confluent/start referenced here is this file, if you just load it before pipe.clj it should work


worth a try!


I added this - if I get some free time I might attempt the fix since I have access to the repo


Thank you very much. I made a lot of progress in setting this up. Anyway, I try the word-count.clj example now, and I found some errors there too, I make a post about it in #jackdaw .


oh, nevermind, I succeeded 😄


please do follow up on my bug ticket above with what worked if you have a chance! I didn't get around to digging deeper into this yesterday


well it didn’t, I started confluent separately, and moved to the word-count example, and that one worked well with clj -A:dev. Now I can learn more about it.


What are some good Clojure books for someone who is not completely new to the language, but also haven't fully grokked it? (Yes, I.) I enjoy 4clojure and other puzzles, but feel the need for something more systematic. I don't mind if it gets advanced, but it needs to start reasonably basic. And if there is some video course that I should consider, those tips are welcome as well.


Nice! Is it up-to-date, you think?

Linus Ericsson15:01:34

I would consider the videotutorials at:

❤️ 8

(btw. Packt Publishing has an offer right now, many ebooks for $5, also Clojure!)

❤️ 4

Not much but maybe one can find something useful there


Are the clojure books available on packt good? IME the quality of their books is usually questionable


not exceptionally great at least 😄 but they are also not horribly bad


I really liked, unlike many of the other introductory/mid-level clojure books it's more focused on the application side and has a lot of hands on examples with full-stack development. The Programming Clojure book (;qid=1579709713&amp;s=books&amp;sr=1-2) was also fantastic, and is a step above in difficulty than Getting Clojure

❤️ 4

Zack Tellman's book is excellent as well:


imo it transcends just Clojure

Eamonn Sullivan16:01:43

+1 on Programming Clojure (by @U064X3EF3). I'm a Scala programmer, so not completely new to functional or the JVM and found it hit the sweet spot. I've also read Elements of Clojure and found it more thought provoking than immediately useful. I'm in the middle of Getting Clojure and I'm finding it a bit too basic for me.

❤️ 4

“Elements of Clojure” is more of a best-practice and patterns book, isn’t it? @U06DEA21F


not really explaining the language


for that purpose it is great, though

Eamonn Sullivan16:01:52

I mostly stopped reading programming books years ago (I have a ton of O'Reilly books), but since I'm doing Clojure as a side project and all by myself, I feel I need a bit more of an overall feel/high-level guidance than what you get in random StackOverflow posts.


same here… reading other project’s code helps


Oh yeah Elements definitely transcends just clojure, highly recommended. It provides guidance in the less instructory aspects of a language, like idioms, higher level design, and I particularly liked its section on understanding abstraction. Lots of fun references to completely non-programming texts and interesting reads from philosophy and social theory that have surprising connections to programming in clojure.

❤️ 4

@U4E39A29Y yes, and realistically it's stuff you pick up as you gain experience as a while, written very well


it's probably the second book I'd give to a new hire after they've gained some experience in the language


Surprised no one mentioned Clojure Applied


older but good, Joy of Clojure


@U04V70XH6 Clojure Applied is good as well, I'm partial to the cover, most of these weren't out when I started Clojure so I don't know how great they are from a 'getting started' standpoint


Clojure Applied is good for someone with some Clojure background, wanting to get more advanced/real world insight.

💯 8

I pretty much just buy every Clojure book out there (except the Packt stuff, most of which is awful).


Programming Clojure -> Clojure Applied as the details books. Joy of Clojure -> Elements of Clojure as the rationale/ideas books. Recommend doing the both in parallel.


@UQY3M3F6D, I have watched two of the free videos now. I love the pace. Video/audio resources can sometimes stress me up, because they go a bit too slow. Not these. They are to-the-point and zero-nonsense. There is a pause button there, after all. Really good work, @U07FP7QJ0 ! (I can't afford the payed tier right now, but hopefully my next employer will realize how smart it would be to give me full access.)


And thanks all of you here for all this input! I've started with Brave online. It allows me to fast forward to the pieces that are missing for me. But I see more tips here that I will follow up on.

Alex Miller (Clojure team)20:01:11

Have you filled out the 2020 State of Clojure Community Survey yet? It's a great source of info in understanding the community, and we'd welcome your participation if you have a few minutes.

👍 4

#object[java.util.Locale 0x28caec3 "nl"] is the 0x28caec3 the hashcode?


Answer: no

user=> (import 'java.util.Locale)
user=> (def l (Locale. "nl"))
user=> l
#object[java.util.Locale 0x562fcb0 "nl"]
user=> (.hashCode l)


memory address?




it's a hashcode, but not the same as Object.hashcode()


More convincing 😉

Jakob Riishede Møller21:01:14

Maybe this should have been posted in the beginners channel - bear with me: From "Many languages have both statements and expressions, where statements have some stateful effect but do not return a value. In Clojure, everything is an expression that evaluates to a value. Some expressions (but not most) also have side effects." When I read this, I get the impression that Clojure does not have statements, but isn't (def x (+ 3 4)) equivalent to a statement?


it's an expression with a side effect. it returns the var that it defines


cljs.user=> (def foo 1)


sorry, "evaluates to" the var that it defines

Jakob Riishede Møller21:01:23

Right, but is is the side effect that we are interested in?


it is the side-effect that we are interested in, yes. that's true lots of times. like when we call println


however it's not true "most" of the time. in most well written clojure programs I would say it's probably only true <1% of the time


eh, maybe <10% of the time I guess if you include def defn and ns which as you correctly note are useful for their side-effects

Jakob Riishede Møller21:01:33

I mean: using def is not very "pure" to me

Jakob Riishede Møller21:01:58

but practical, I guess


even haskell let's people define things 🙂


although haskell separates compile/definition time from runtime I guess

kwladyka21:01:46 this is in the topic of side effects. Maybe will be useful.


I am very wrong about definitions but in Clojure data is code and code is data, so: (foo 1 2 3) is a list where first item is a name of the function. But you can generate the same list by other function and run it as you expect or threat as a data only.

Jakob Riishede Møller21:01:01

My point was only, that I suspect def is used a lot to hold state


You will only see def at the top-level


(def hostname (-> (InetAddress/getLocalHost)
^ example of dynamic thing during start the app But in most cases (def conf-status #{3 5}) etc.

Jakob Riishede Møller21:01:28

I am used to OOP and a newbie in functional programming, so that kind of advice is worth remembering


@USNL3G7GE it's not that clojure doesn't have side effects, it that clojure has no forms that don't return a value


oh that was a point of your question, now I see the point 🙂


these things are related, but it's a nuance - you can say (def foo-var (def foo 42)) - foo-var holds the var that holds foo


@@foo-var returns 42, @foo-var returns a var that currently holds 42, but could hold something else later


that's not really what you asked - a lot of things return nil, you can use for example (let [x (f 1) _ (println x) y ...] ..) and clojure doesn't error about the println in a binding context - it returns nil, which is a valid thing to bind to


but don’t bother too much about this theory, this is not something what you would think about during coding later. Things come naturally.


@USNL3G7GE the primary way this comes up: (let [x (if (f) 0 1)] ...) - since everything returns a value, you can use if for a value instead of a side effect, which is very useful

Jakob Riishede Møller21:01:31

I think you should bother about code structure - I cannot imagine that it is not possible to write programs in Clojure with a clumsy structure


oh it is, I saw terrible projects in Clojure, terrible…

Jakob Riishede Møller22:01:35

@U050ECB92 Oh - I guess you meant that def sets global state (and nothing else)


yeah it defines initial meaning


even in "pure" functional systems there is something that does that


binds a symbol to its meaning

Jakob Riishede Møller22:01:08

But I think global state should be minimized...(?)


sure, but you need at least one


the idea with def is we don't use it for in-app logic, we use it for iterative debugging and development of a live system


in order to be productive as a programmer I want to be able to replace the buggy version of f (a globally visible function) with a new one, that's a mutation but it's not a mutation in my app logic, just my dev flow


it's not global mutable state it's a constant that's being defined

Jakob Riishede Møller22:01:45

So just dont redefine it 😉


Well, a mutable constant 🙂


I realize that isn't necessarily clarifying anything for someone just learning it, but it really is mutable, since you can change it at run time. It is considered good style/practice to def a function at run time when developing, to fix things or try things out. It would be considered bad style/practice by most Clojure devs to do that in a production system, except perhaps in emergencies involving manual intervention by a live human, which is like the development time scenario.


And that last scenario would be considered bad practice by many developers.