Hey guys, a little confused by this behavior. (defn vector-X-Long [x] (loop [itr 0 arr []] (if (= itr x) arr (recur (inc itr) (conj arr itr))))) (defn create-data [dates] (->> dates (map (fn [x] {x {:booked? false :nameOfEvent :nothingBookedYet}})) (into {}))) (def lost (create-data (vector-x-long))) Why doesnt this return the hashmap in order. ex. {0 {}, 1 {}, 2 {}, 3{} ...} Instead it returns what feels like randomness. When I println x inside create-date its in order. How could I get it for (def lost) to be in order?
probably best for #beginners but maps are not ordered
(seq {:a 1 :b 2 :c 3 :d 4})
=> ([:c 3] [:b 2] [:d 4] [:a 1])
(seq (into (sorted-map) {:a 1 :b 2 :c 3 :d 4}))
=> ([:a 1] [:b 2] [:c 3] [:d 4])
Is anyone here aware of any work done to integrate https://www.oracle.com/corporate/features/understanding-java-9-modules.html into a clojure project ? By that I mean, structuring a large clojure project into Java 9 modules and composing them into services etc.
(with-redefs [inc (fn [v] (+ 2 v))]
(inc 2))
=> 3
what am I doing wrong ? (I was expecting 4)maybe (inc 2)
is inlined, hence the compiled code doesn’t do var dereferencing at all
^^
Hackety hack:
(def inlined (atom {}))
(defmacro un-inline [var-sym & body]
`(do (swap! inlined assoc (var ~var-sym) (:inline (meta (var ~var-sym))))
(alter-meta! (var ~var-sym) dissoc :inline)
(try ~@body
(finally
(alter-meta! (var ~var-sym) assoc :inline (get @inlined (var ~var-sym)))))))
(un-inline inc
(with-redefs [inc dec]
(prn (inc 1)))) ;; 0
(with-redefs [inc dec]
(prn (inc 1))) ;; 2
keep in mind even that won't work if you call something in core that calls inc, because it's pre-compiled (with direct linking)
I mean, even w/o direct linking it would've already been ... inlined
yep
Pretty much everyone ignores modules
yeah, you would have to reload those namespaces in the body of un-inline. veery hacky
Ok 🙂 What would be the preferred method to organise a large Clojure project and get features like dependency management and modularisation between groups of namespaces, without going down the road of full fledged libraries and services ?
I'm trying to use Clojure to write a Sonarqube plugin (which expects Java). I have it loading my plugin, but then it crashes with Could not locate clojure/core__init.class, clojure/core.clj or clojure/core.cljc on classpath
presumably b/c it loads plugins in their own isolated classloaders but Clojure uses its own (or something like that; I'm a bit out of my depth here). Anyone run into something like that before? Clojure and spec are in the jar file in META-INF/lib
, so it seems to be related to the classloader thing.
@cap10morgan did you end up getting this all worked out?
I did not. Thanks for the link! Reading it now.
hmm... interesting. I'm not sure anything like this exists in Sonarqube (what I'm trying to write a plugin for), so I'm trying to set Clojure's classloader to the one Sonarqube is using for the plugin. It gives a custom classloader to each plugin.
As a leiningen user so far, I've come across practicalli/clojure-deps-edn and wanted to try it on a new piece of code. However, on a simple clojure -X:project/new
I just receive an error message: No function found on command line or in :exec-fn. Searching the tubes for this doesn't reveal anything helpful -- any idea what might be wrong here?
@schaueho I think you will need to setup your ~/.clojure/deps.edn
file correctly for that to work.
Looks like the example deps.edn in that GH repo has what you want.
well, I followed the instructions on the practically/clojure-deps-edn repo and so my ~/.clojure/deps.edn actually contains a :project/new
alias
that's why I'm puzzled why it doesn't work
Clojure tools are also updated to 1.10.1.727
I copied the :project/new alias from that repo into my ~/.clojure/deps.edn and was able to successfully run clojure -X:project/new
so must be something in the setup
clj -Srepro -Sdeps '{:aliases {:project/test {:replace-deps {seancorfield/clj-new {:mvn/version "1.1.226"}} :exec-fn clj-new/create :exec-args {:template lib :name practicalli/playground}}}}' -X:project/test
^^ can you try that one-liner? it ignores your ~/.clojure/deps.edn
this works
it also works when I copy the deps.edn file to a separate directory and run the command from there, so I guess somehow the deps.edn is not getting picked up from ~/.clojure/
^^ it meaning clojure -X:project/new
@schaueho Maybe there's a typo in your ~/.clojure/deps.edn
file? Could you share it, or at least part of it that's relevant to this issue?
can you clj -Sdescribe
and look at the output to see if :config-user points at ~/.clojure/deps.edn ?
could be different if you have $CLJ_CONFIG or $XDG_CONFIG_HOME set
@seancorfield it's a clone of the current practically/clojure-deps-edn repo that I didn't edit
I checked the practicalli/clojure-deps-edn file and it works fine for me
@alexmiller actually it doesn't, it points at :config-dir "~/.config/clojure"
well there you go :)
you probably have XDG_CONFIG_HOME set
in that case, config will be at $XDG_CONFIG_HOME/clojure
you can override that by setting CLJ_CONFIG to your ~/.clojure if you want
see https://clojure.org/reference/deps_and_cli#_deps_edn_sources
thanks a ton!
I've experience a similar-seeming issue w/ Quartz before, maybe this helps? http://clojurequartz.info/articles/durable_quartz_stores.html#quartz_and_clojure_class_loaders
Hey, I probably did something stupid and can't use either clj
or clojure
. lein repl
still works fine. Could anybody help me figure it out?
clojure -Sdescribe
output:
{:version "1.10.1.708"
:config-files ["/home/myuser/.clojure/deps.edn" ]
:config-user "/home/myuser/.clojure/deps.edn"
:config-project "deps.edn"
:install-dir "/usr/clojure"
:config-dir "/home/myuser/.clojure"
:cache-dir "/home/myuser/.clojure/.cpcache"
:force false
:repro false
:main-aliases ""
:repl-aliases ""}
"can't use" - what specifically fails?
Yeah, sorry, I sent the message accidentally
Error: Could not find or load main class clojure.main Caused by: java.lang.ClassNotFoundException: clojure.main
This is the output for both clj
and clojure
"/usr/clojure" is a weird install location
I'm on OpenSUSE btw
If I'm not mistaken I just installed it via YaST2's GUI (which I suppose is OpenSUSE's official way)
I don't recall setting any paths manually
I just checked, /usr/clojure
doesn't exist
so -Sdescribe
is mistaken, or exposing some misconfiguration?
I suppose... How can I find out?
Is opensuse Debian based? I know there’s a package there called clojure that is a bad wrapper
opensuse is derived from redhat, but split a long time ago
the debian clojure just wraps clojure.jar, and has none of the cli features, yeah
it wouldn't be able to produce the "-Sdescribe" output
@edjroot you could try downloading from http://clojure.org and installing the scripts to ~/bin
or /usr/local/bin
- it's pretty simple
https://clojure.org/guides/getting_started#_clojure_installer_and_cli_tools
beyond what it provides, all it needs is java
to be on path
Alright, I'll do that and let you know if it works, thanks!
Isn't it weird that lein repl
works though?
not at all - clojure is just a jar that you put on the java classpath
it doesn't use any global installation that clj / lein would share
both use .m2
to cache deps, but that isn't used for clojure itself on startup
Oh, that makes sense
getting down to the basics, clojure is a java library, providing a clojure.main
class with a -main
entrypoint that runs a REPL compiling clojure code to bytecode and running that bytecode
Since there's a brew tap for clojure/tools/clojure
that is maintained by the Clojure team, I've found it worth installing linuxbrew and using that to keep my CLI install up-to-date.
fyi, homebrew core tap is now being kept up to date with stable releases from clojure/tools/clojure. and linux tap is tracking that one, so while there is a lag of couple days for each hop there, they should all be showing you approximately the same thing these days.
So, before trying the CLI method I actually uninstalled and installed it again via YaST2 and now it works... Go figure 🙂 Thanks a lot for the quick and helpful responses!
Is it possible to change what a var points to at compile time? Example is I want to replace clojure.core/memoize
with my own version.
Compile-time is all of the time in Clojure 🙂
The smiley is there because it isn't strictly true, but it is true that whether you are loading code from a file or entering expresssions at a REPL, all top level forms are compiled before they are evaluated. You can use things like alter-var-root
to modify the root binding of a Var. If there is a call to that at the top level in a file that you load or require, then it will be evaluated and take effect while loading/requiring that file.
This is what I wasn’t sure about. Like most uses of memoize will be (def my-fn (memoize my-fn*))
, so it seemed like it would be too late to catch those cases if I just alter-var-root
If you do not compile Clojure with direct linking, which is disabled by default, then whenever memoize is called, it will dereference the Var's current value.
That is why in a REPL you can use defn
to redefine a function foo
, and with a few exceptions, other functions defined earlier that call foo
will call the updated version.
Oh, in your case, you will want to make sure that alter-var-root
is evaluated before you evaluate that def
form.
Because using alter-var-root
after such a def
form, yes, memoize
will have been deref'd at the time that def
form is evaluated.
OK, then I will give it another go but try to be more careful about when it’s called. Basically I’ll need to alter-var-root before I do any requires of code that will use it.
There may be easier ways to do it in your code base, but if you have some kind of utils
namespace that is require'd by most or all of your namespaces, you could put the alter-var-root
in there and know that it will take effect before any namespace that require
's that one
Then again, if you have that, then you could instead define your own memoize-like function, and call it instead of clojure.core/memoize throughout your code base, but I'm guessing if you were willing to do that, you wouldn't have asked 🙂
In this case I’m actually trying to target a third party lib.
But I think I can create an entrypoint where I do setup and then do a (require …)
vs using ns
welcome to monkey patching!
Hi! I'm follwowing the current beta of Dmitry Sotnikov's Book on Luminus. I have started over three times by now due to a bug that leaves me mystified, but that inevitably seems to creep up at some point. I get the following error when I try to start the application (once the REPL has started):
Execution error (AssertionError) at ns-tracker.dependency/depend (dependency.clj:57).
Assert failed: self-referential dependency
(not (= x dep))
As far as I can remember, on each occasion the last thing I did before this happened was wiping one of my database tables – hardly something that I'd expect to lead to an NS-problem.
Here's what I know:
1. I definitely have no circular dependencies among my own namespaces
2. All I did was manipulate the DB. Most imortantly none of my clojure namespaces have changed.
3. The Problem is related to Ring's `wrap-reload` middleware, which apparently does it's own dependency-checking. When I remove it from my dev-middleware-chain everything works (except reloading, obiously). I can also create an uberjar without problems.
I know that certain people discourage the use `wrap-reload` in general (as Sean Corfield did in reply to a https://clojurians-log.clojureverse.org/beginners/2020-10-06. However, I can hardly believe that this kind of error is intractable to the point that I have to switch build tooling…
Any ideas on where this might stem from? (edited)
you should revisit assertion #1
because that error indicates ns-tracker (which is used by wrap-reload) disagrees and thinks you do
Is it really possible to compile the project into an uberjar in that case?
it is complicated
Well… I guess the circularity might only be resent in the dev-build…
so yes, it is possible I guess in the answer
and ns-tracker and clojure itself may not agree on how they detect circularity
But then, according to https://www.reddit.com/r/Clojure/comments/8cs5hg/what_does_self_referential_dependency_mean_and/, the circularity might be in one of my dependencies (read: libs)
very unlikely
hm… I can, of course re-check, but as I said: None of my Clojure source-files have changed… only in CLJS… and even there the ns declarations
did not…
(thanks for taking the time btw)
one of the reasons some people discourage the use of things like wrap-reload is the code reloading is a complicated thing to do, and the state you get into with reloading is very unlikely to be exactly the same as the state you get when starting the system fresh
so if you have been going on and everything has been working fine using reloading for a while, then you kill and restart the process for some reason, and then things are broken, the change that caused the breakage could have been sometime ago and just happened to continue to work with reloading for whatever reason
but I would strongly suggest you go over your code with a fine tooth comb before you start looking at libraries
like, I've seen things where people where trying to debug something not behaving as they expected and it ended up they had two checkouts of the code and were editing and running different checkouts
I understand that… actually I'd even prefer to use something a bit simpler (not albeit not easier than leiningen): My first go was with boot… but I found my progress greatly hampered by dealing with build troubles 60% of the time when my actual goal was to grok Luminus…
I doubt it is a build tool issue
the assertion that is failing is a check that fails when a namespace literally depends on itself
like if you had (ns foo (:require foo))
I gathered as much (I have dealt with circular dependencies on quite a number of occasions before)… I'll check again… I guess there's no way to find out which ns is actually offending?
there is a pr on the project to include the offending ns in the message
pr? pull request?
yes
what steps exactly do you take before you see the error?
ok, sorry if this is a dumb question… so the project you're talking about would be Ring?
no
ns-tracker
Ok, thanks for you patience: here's how I reproduce it:
1. Jack-in CIDER → REPL Starts, all good so far
2. In user ns: (start)
3. I get this:
2020-11-19 00:27:38,376 [nREPL-session-d79a4c6f-7e7b-4cf4-bed5-9bb3c6896d1d] INFO guestbook.env -
-=[guestbook started successfully using the development profile]=-
Execution error (AssertionError) at ns-tracker.dependency/depend (dependency.clj:57).
Assert failed: self-referential dependency
(not (= x dep))
depending on what steps happen before you get the error, you may be able to run code before the error happens, which will allow you to change the definition of the function throwing the error to print out its arguments before throwing the error which will tell you which ns it is
I get something more detailed when I do it on the console with lei run
(which also uses the dev profile)
there's also lein check
which simply loads up every clj file on local path, and it should hit an error and report it, it definitely tells you which file blew up
running lein check
now…
run (alter-var-root (requiring-resolve 'ns-tracker.dependency/depend) (fn [orig] (fn [& args] (prn args) (apply orig args))))
before calling start
using lein run
generates the following “full report”
the last thing that gets printed out will include the name of the offending namespace
lein check
shows no errors… just one warning that does indeed smell a bit of “circularity”: Reflection warning, guestbook/core.clj:56:42 - call to java.lang.Thread ctor can't be resolved.
that has nothing to do with circularity
@hiredman I'll run your command right now
it may print out a lot
(thanks again to both of you for your time and patience)
@hiredman your command returns a function #function[user/eval29638/fn--29639/fn--29640]
sure, after you run it call start
then you'll get print outs of the arguments to the depend function as ns-tracker uses it
and the last print out will be the arguments it is called with before the assertion error
Yep… got a big printout
the arguments will generally be a list, the first element being a big map, the rest of the arguments are namespace names
The last thing printed is this:
({:dependencies {guestbook.routes.home #{guestbook.validation struct.core guestbook.layout guestbook.middleware ring.util.http-response <http://clojure.java.io|clojure.java.io> guestbook.db.core ring.util.response}, guestbook.handler #{mount.core guestbook.layout guestbook.routes.home reitit.ring ring.middleware.content-type guestbook.env guestbook.middleware ring.middleware.webjars}, guestbook.middleware.formats #{luminus-transit.time muuntaja.core}, guestbook.core #{guestbook.nrepl mount.core guestbook.config luminus-migrations.core luminus.http-server clojure.tools.logging clojure.tools.cli guestbook.handler}, guestbook.db.core #{conman.core mount.core guestbook.config next.jdbc.date-time next.jdbc.result-set}}, :dependents {guestbook.validation #{guestbook.routes.home}, guestbook.nrepl #{guestbook.core}, conman.core #{guestbook.db.core}, mount.core #{guestbook.core guestbook.db.core guestbook.handler}, guestbook.config #{guestbook.core guestbook.db.core}, struct.core #{guestbook.routes.home}, next.jdbc.date-time #{guestbook.db.core}, guestbook.layout #{guestbook.routes.home guestbook.handler}, guestbook.routes.home #{guestbook.handler}, reitit.ring #{guestbook.handler}, luminus-migrations.core #{guestbook.core}, luminus.http-server #{guestbook.core}, luminus-transit.time #{guestbook.middleware.formats}, clojure.tools.logging #{guestbook.core}, ring.middleware.content-type #{guestbook.handler}, muuntaja.core #{guestbook.middleware.formats}, guestbook.env #{guestbook.handler}, next.jdbc.result-set #{guestbook.db.core}, guestbook.middleware #{guestbook.routes.home guestbook.handler}, clojure.tools.cli #{guestbook.core}, ring.util.http-response #{guestbook.routes.home}, <http://clojure.java.io|clojure.java.io> #{guestbook.routes.home}, guestbook.db.core #{guestbook.routes.home}, ring.middleware.webjars #{guestbook.handler}, guestbook.handler #{guestbook.core}, ring.util.response #{guestbook.routes.home}}} guestbook.db.core guestbook.db.core)
so ns-tracker thinks guestbook.db.core depends on guestbook.db.core
fascinating… ok… I'll have another look at this ns…
Ok… this is really embarrassing…
`(:require [next.jdbc.date-time] [next.jdbc.result-set] [conman.core :as conman] [mount.core :refer [defstate]] [guestbook.config :refer [env]] ;; [java-time :refer [java-date]] [guestbook.db.core :as db])`
more embarrassing then that guy who had two code checks and was editting one and running the other?
I have no idea how I managed to do an then miss this…
well, someday that pr will get merged and it won't be a big mystery
I was actually looking for exactly this kind of thing (because it was what I understood the error to mean)
Still… I was lucky to have someone with a thorough knowledge ot ns-tracker's inner workings
I have an hypothesis as to how this came about… but I feel I've been bothering you long enough…
If we weren't in lockdown I'd buy you a pint…
Anyway: thanks again (looking forward to that pr)!
what's the hypothesis?
we've come so far on this journey 🙂