clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
yuhan 2021-03-30T07:47:01.078600Z

Is there a more idiomatic way to reduce over multiple collections?

(reduce (fn [acc [x y z]]
          (assoc acc x (str y z)))
  {}
  (map vector
    [:a :b :c]
    (range)
    [:d :e :f]))
I always feel somewhat icky about zipping them into intermediate tuples only to destructure immediately - as if there should be a sort of multi-arity (reduce (fn [acc x1 x2 & xs] ...) init c1 c2 & colls) without the "overhead"

➕ 1
2021-03-30T08:23:05.078800Z

(reduce (fn [acc f]
          (f acc))
        {}
        (sequence (map (fn [x y z]
                         #(assoc % x (str y z))))
                  [:a :b :c]
                  (range)
                  [:d :e :f]))
transducers ❤️ )

💥 3
4
🤯 2
raspasov 2021-03-30T08:26:06.079Z

@delaguardo wow 🙂 Have never thought of having the “item” in reduce be a function, cool.

2021-03-30T09:14:13.079700Z

Luxury of fp)

yuhan 2021-03-30T09:57:25.080200Z

That's a really neat and mind-bending solution 🙂 Although in a sense it's just swapping the intermediate collections for intermediate anonymous functions?

yuhan 2021-03-30T09:57:51.080400Z

(Not that I've tried profiling to compare the two, performance isn't really a concern)

flowthing 2021-03-30T10:03:18.080600Z

I guess (into {} (sequence (map #(vector %1 (str %2 %3))) [:a :b :c] (range) [:d :e :f])) also works, although I'm not sure about the performance characteristics. No need to destructure, at least. :man-shrugging::skin-tone-2:

yuhan 2021-03-30T10:13:22.080900Z

yeah that works for this toy example, but in general there would be more logic going on in the reducing function than a plain assoc

flowthing 2021-03-30T10:14:02.081100Z

Right, gotcha.

pieterbreed 2021-03-30T11:36:33.093Z

Hello everyone. I'm having a really confusing past two days. Clojure code that has been stable for months/years and have been running and building correctly (`lein`) is now giving me weird errors when I try to run and/or build. The errors started on dev laptops (Mac OSX) and on our CI servers (linux) at the same time. An example; one of my namespaces has (:require ... [clojure.core.async :as csp] ...) and then when I run I get java.lang.RuntimeException: No such var: csp/to-chan!. This code has been in production for nearly two years at this point, except now it's not loading/running properly any longer. Maybe it's also good to mention that we're using integrant and using integrant.core/load-namespaces to require the namespaces dynamically based on an integrant config file. Any help and/or pointers would be appreciated.

p-himik 2021-03-30T11:46:17.093100Z

Something must've changed and you now have an older version of org.clojure/core.async on your classpath.

p-himik 2021-03-30T11:46:43.093300Z

to-chan! has been added in 1.2.598.

p-himik 2021-03-30T11:47:20.093500Z

Oh wait, it's for CLJS, nevermind.

p-himik 2021-03-30T11:48:24.093700Z

1.2.593 for CLJ.

pieterbreed 2021-03-30T11:49:31.093900Z

Our lein deps :tree is clean, with no dep conflicts. It shows I have only [org.clojure/core.async "1.3.610"]

p-himik 2021-03-30T11:51:29.094100Z

Just to be absolutely sure - can you see what version is used in the output of (System/getProperty "java.class.path")?

p-himik 2021-03-30T11:51:54.094300Z

Not in a separate REPL but right in the same process where that error happens.

pieterbreed 2021-03-30T11:54:39.094500Z

buried in there: .m2/repository/org/clojure/core.async/1.3.610/core.async-1.3.610.jar

p-himik 2021-03-30T11:56:13.094700Z

One other potential reason is that something is either an uberjar with core.async in it or it ships its own core.async along with its sources.

p-himik 2021-03-30T11:57:16.095Z

I'm not sure what the best way of checking that would be, but you can at least try running:

(require '[clojure.core.async])
(:file (meta #'clojure.core.async/tap))
and see if it output anything other than "clojure/core/async.clj".

👍 1
pieterbreed 2021-03-30T11:58:05.095200Z

so maybe I should expand a bit here: This to-chan! is a symptom of a bigger issue we are having. Previously (earlier today) I had no such var on symbols in our own namespaces. I then modified our own namespaces with (println ...)'s (to introduce side-effects). Those println's changed the behaviour of the bugs to such an extent that we're now getting this no such var on a namespace that I cannot modify...

p-himik 2021-03-30T11:58:52.095500Z

Oh. No clue what's going on then. Maybe something is modifying existing namespaces in runtime?

pieterbreed 2021-03-30T11:59:15.095700Z

I got "clojure/core/async.clj" on that suggestion of yours

raspasov 2021-03-30T12:18:48.095900Z

Have you added new dependencies recently or bumped any versions?

pieterbreed 2021-03-30T12:23:19.096100Z

We keep our dependencies as up-to-date as possible (running lein ancient as part of CI) However, our dependencies are still the same as they were early last week when we did have builds working. Something in the environments may have changed (eg brew upgrade), but I don't know how to determine that.

raspasov 2021-03-30T12:29:56.096300Z

Hmm… Check what version of java you’re running against; make sure “brew upgrade” etc hasn’t installed some esoteric JVM that is not supported (I’ve tried a few intentionally recently and they didn’t work); are you able to build at least once anywhere locally or on a new machine?

raspasov 2021-03-30T12:32:26.096500Z

As a last resort, try running your project in a Docker container with one of the pre-built Clojure Docker setups on Docker Hub; at least it will give you pretty much a 100% guarantee of a stable environment.

pieterbreed 2021-03-30T12:33:42.096700Z

I will try this docker suggestion: lein version gives me this: Leiningen 2.9.5 on Java 15.0.2 OpenJDK 64-Bit Server VM

pieterbreed 2021-03-30T12:35:21.097400Z

Does a call to (require ...) perform any work in a background thread? IE, can it return before it completes loading all the namespaces?

raspasov 2021-03-30T12:41:15.097500Z

Java 15 OpenJDK should work…

thheller 2021-03-30T12:46:22.098Z

no threaded work but it is not thread-safe which can lead to code trying to use vars that have not been loaded yet

raspasov 2021-03-30T12:51:24.099900Z

@thheller Is that assuming that you’re calling (require …) from the middle of a namespace somewhere? Or if you’re using top-level (:require …) it can still happen?

raspasov 2021-03-30T12:54:08.100600Z

@pieterbreed perhaps reading through this can be of some help (if your problem is related) https://ask.clojure.org/index.php/9893/require-is-not-thread-safe

👍 1
pieterbreed 2021-03-30T12:56:11.101300Z

I don't really understand what this means... The thread that runs my main does a whole bunch of dynamic requires, after that, it starts the system which then starts a number of threads... Am I to believe that require may return without those namespaces being ready?

raspasov 2021-03-30T12:56:42.101500Z

That’s probably the root cause of your issue, if I have to bet

raspasov 2021-03-30T12:57:25.101900Z

;; Note that require is known _not_ to be thread safe in Clojure 1.10.x and
;; earlier, so avoid calling it concurrently from multiple threads.

;; See <https://ask.clojure.org/index.php/9893/require-is-not-thread-safe>
;; for some thoughts on approaches to using require from multiple threads
;; safely, which today boils down to "use locks to make all calls to require
;; guaranteed to execute one at a time".

pieterbreed 2021-03-30T13:02:50.102200Z

those require's are only invoked serially from a single thread, that waits for them to complete... then it starts doing business logic... is this not safe?

raspasov 2021-03-30T13:03:23.102400Z

Perhaps not … I am not 100% sure

raspasov 2021-03-30T13:03:51.102700Z

But I’d try replacing those dynamic requires with:

(#'clojure.core/serialized-require 'tick.alpha.api)
(needs 1.10 and the #’ because serialized-require is private)

👍 1
raspasov 2021-03-30T13:05:32.103Z

All it does is it just wraps require in (locking …)

(locking clojure.lang.RT/REQUIRE_LOCK
  (apply require args))

p-himik 2021-03-30T13:12:27.103200Z

> We keep our dependencies as up-to-date as possible (running lein ancient as part of CI) Just wanted to comment on this specifically - I don't think it's a good practice to do that automatically. Detect and notify automatically - fine. But not update. You can never know what the actual changelog will have between x.y.z and x.y.(inc z).

raspasov 2021-03-30T13:12:35.103400Z

I am guessing that even though the require is invoked serially from one thread, later when your business logic starts, if that’s on different threads (and I bet it probably is, thread pools and all of that), that’s where you might run into issues;

raspasov 2021-03-30T13:14:33.103600Z

I agree with @p-himik

raspasov 2021-03-30T13:21:19.103800Z

@pieterbreed or perhaps you can use the public requiring-resolve Let me know how it goes, curious if this fixes it.

⭐ 1
pieterbreed 2021-03-30T13:24:06.104Z

Thank you @raspasov, I'll try this and see how it goes. Thanks for the engagement :thumbsup:

🤝 1
raspasov 2021-03-30T13:26:26.104300Z

Also, if you have Java code calling Clojure, that can be another possible cause… Attempting to do multithreaded programming is one of the most humbling things I’ve done. It will often prove me wrong even after multiple iterations and when I’m internally convinced that I finally “got it” 🙂 And that’s in Clojure, with all the help from immutability. Can only imagine doing it in C++/Java or something like that.

thheller 2021-03-30T13:41:43.110Z

it is useful to understand how clojure loads code. it processes one form at a time sequentially. so it usually processed a ns form first, then a defn then the next etc

thheller 2021-03-30T13:42:42.110200Z

so if you are in a threaded scenario with two require running you can end up there on ns is trying to use a defn from another ns but failing since the original thread hasn't processed that yet

thheller 2021-03-30T13:43:40.110500Z

but if you run all require sequentially from that one thread that can't happen

pieterbreed 2021-03-30T13:53:52.115400Z

What’s truly weird is this: we’ve been getting “no such var” type errors in namespaces which are ours. We’ve gone and added (println ::loading) to those same namespaces, right below the ns form, and then magically the errors move to a different “place”. Finally, we got it to this point where we are getting “no such var” on core-async. Why would adding println’s affect this?

pieterbreed 2021-03-30T13:57:41.118900Z

These points are valid; however for us, it’s been easier to run into compatibility problems sooner rather than later. Also, staying up to date incrementally is easier than trying to catch up in bulk from versions that are old, like when a bugfix is only in a version that’s recent.

thheller 2021-03-30T15:19:04.119400Z

well sounds like you are racing and adding a println is going to make the one thread a tiny bit slower since it has to compile and execute the print

thheller 2021-03-30T15:19:43.119600Z

thus given the other thread a little bit more time to make further progress. definitely use a lock if you are using require dynamically

michaelb 2021-03-30T17:47:18.120600Z

not sure why, but I’ve started getting email from the Clojure Jira

michaelb 2021-03-30T17:47:42.121200Z

I think I submitted a ticket or two maybe ~7 years ago

alexmiller 2021-03-30T17:51:07.121600Z

sorry, should be fixed (wrong change to a notification scheme)

👍 2
1
dpsutton 2021-03-30T18:00:09.122700Z

Does anyone use clojure.core.logic.unifier? Interested to know how you leverage it

vemv 2021-03-30T18:39:16.122900Z

I'd try hard to use either tools.namespace or Clojure's vanilla require system. Alternatives can be less polished/understood I'd also try to take threading out of the equation - all requires should happen in the main thread

vemv 2021-03-30T18:41:45.123100Z

It's not the first time you are experiencing issues btw :) https://github.com/adambard/failjure/issues/24 Personally I'd use that as evidence that a simple/standard system would be the best best

pieterbreed 2021-03-30T19:50:26.126800Z

Hi, yes, you are right. I do think these issues are all related. I am only using require and only from the main thread before any business logic starts, so I’m uncertain how to improve things.

vemv 2021-03-30T22:55:32.127200Z

As you may have noticed integrant.core/load-namespaces performs some requires, so I'd try to investigate in which conditions you are invoking load-namespaces (no threads, retries, try/catch, etc...?)

vemv 2021-03-30T22:57:47.127400Z

Did you see https://github.com/weavejester/integrant/issues/52 as well?

agentfunk 2021-03-30T23:46:32.129600Z

Hi everyone, I'm struggling to create an uberjar using depstar while excluding a jar that is provided by the platform. Basically, something like <scope>provided</scope> in maven for deps.edn. Is there a way?

seancorfield 2021-03-30T23:54:00.130Z

@sammerat What have you tried so far?

agentfunk 2021-03-30T23:56:18.131200Z

@seancorfield Thanks for the response Sean. I tried {:mvn/version "2.2.0" :scope "provided"} but it looks like it is still getting bundled

seancorfield 2021-03-30T23:56:43.131600Z

tools.deps.alpha doesn’t pay any attention to :scope as far as I know.

seancorfield 2021-03-30T23:57:24.132400Z

What library are you trying to exclude and why? An uberjar is intended to be a standalone runnable bundle.

agentfunk 2021-03-30T23:58:19.133500Z

@seancorfield I'm building an apache storm topology which depends on strom-client.jar which is also provided by the storm runtime

seancorfield 2021-03-30T23:59:17.134200Z

So you need the JAR on the classpath for compilation, but not included in the final (uber) JAR?

agentfunk 2021-03-30T23:59:31.134500Z

exactly