Fork me on GitHub
#clojure
<
2022-03-09
>
Ian Fernandez02:03:54

I want to try a s-expr for every stuff that I required, when this s-expr won't throw an exception I would like to see for which module it happened

Ian Fernandez02:03:03

is that possible?

Ian Fernandez02:03:13

like, right now I'm copying the verbose output from a require and I'm thinking on doing a (doseq [s-expr forms-list] (try (my-stuff) (catch e (prn "not passed"))) (eval s-expr)) for each one

hiredman02:03:56

What you want is a function

Ian Fernandez02:03:31

is there a function for it?

hiredman02:03:32

Instead of writing s-expressions and evaling then, write functions and call them

Ian Fernandez02:03:34

instead of using the s-expr from verbose print

Ian Fernandez02:03:22

you're telling me to make (fn [] (s-expr)) ?

hiredman02:03:24

Dunno exactly what you are doing

Ian Fernandez02:03:33

I'm picking every in-ns, alias and loading that comes from the :verbose inside a require in a namespace

hiredman02:03:38

If you are reading forms from a file then evaling them that is an appropriate use of eval, if you just have a list of expressions you are evaling, the correct thing is to write functions and call those functions instead of using eval

Ian Fernandez02:03:54

and I want to eval 1 expression before each require

Ian Fernandez02:03:30

Right now I'm copying the output from the :verbose making a list and trying to do this

Ian Fernandez02:03:55

I'm doing that because there is a java mutable object that is being evaluated inside some ns require

Ian Fernandez02:03:08

that I need to know which one of those are mutating this java object

Ian Fernandez02:03:58

Dealing with some legacy strange code hehe

jaide02:03:37

Would it be possible to write a new clj file that requires those same files and run that as the entry point like clj debug-files.clj then comment out each import until you pinpoint the one executing arbitrary java?

👍 1
hiredman02:03:32

Or just grep it

hiredman02:03:50

Search for the method that is being called

jaide02:03:52

(ns proj.debug-files
  (:require 
   [proj.module-a :as a]
   [proj.module-b :as b]
   [proj.module-c :as c]))

 (my-stuff)
As an example, can be done with java imports as well, assuming grep is not an option

hiredman02:03:07

Using with-redefs to redefine clojure.core/load, so you can check the state of the java object before and after each load, and use tools.namespace to find all the clojure code to load

👍 1
1
Ian Fernandez03:03:45

I’ll try this with-redefs this sounds an interesting idea

p-himik07:03:00

Wouldn't it be easier with a regular debugger and breakpoints in all the mutating methods?

Ian Fernandez16:03:45

I've tried:

(with-redefs [clojure.core/load (fn [& paths]
                                  (try (get-all)
                                       (catch Exception e
                                         (println paths)
                                         (println "Not loaded")))
                                  (clojure.core/load paths))] (require ,,,, :verbose))

Ian Fernandez16:03:57

got some strange error

hiredman16:03:01

Stackoverflow because you can redefining clojure.core/load, and then calling the new definition in the new definition

hiredman16:03:56

The example gist captures the original value of load before redefining load, and invokes the original load or does the other thing as needed

Ian Fernandez19:03:03

(let [orig-require @#'clojure.core/require]
 (with-redefs [clojure.core/require (fn [& args]
                                     (try (do (get-all)
                                              (throw (Exception. "WORKED!")))
                                          (catch NullPointerException e
                                            (println args)
                                            (println "Not loaded")))
                                     (apply orig-require args))]  ,,,,)

Ian Fernandez19:03:05

better one:

(let [orig-require @#'clojure.core/require]
  (with-redefs
    [clojure.core/require
     (fn [& args]
       (try
         (let [v (get-all)]
           (println "Foi")
           (throw (ex-info "FOI!"
                    {::args args
                     ::v    v
                     ::ok   42})))
         (catch Exception ex
           (if (::ok (ex-data ex))
             (println "FOI!" (ex-data ex))
             (throw ex))))
       (apply orig-require args))]))

hiredman19:03:30

@#'clojure.core/require <=> clojure.core/require

hiredman19:03:36

the nice thing about intercepting calls to load vs. require is load is a much simpler function, the argument is just string instead of require's whole dsl, and load is downstream of require, and require checks to see if something was already loaded and then doesn't load it, so you won't get duplicate calls to load

1
hiredman19:03:32

the whole exception thing is bonkers

hiredman19:03:09

if you get rid of the try/catch and put the println from the if in the try in place of the throw it will behave the same, unless get-all is also throwing exinfos with ::ok in them

👍 1
jaide02:03:11

How do I export fns I'm requireing in my core.clj for other modules to conveniently use? For example, let's say I have a utils.clj that I want to also expose clojure.pprint/pprint so I can do (require '[my-app.utils :refer [pprint]]) in my app

pavlosmelissinos07:03:14

You can do it explicitly in utils.clj: (def pprint clojure.pprint/pprint)

pavlosmelissinos07:03:18

To be honest though, if you're using pprint I don't see the point in not requiring the namespace directly. In other languages like python you can transitively call functions from modules that are imported but that's not as easy in clojure. You can do it with macros but I'm not a fan.

jaide08:03:43

If you do the def format so you lose the docstr? Agree that using pprint like that would be impractical but was trying to come up with a simple example.

pavlosmelissinos10:03:37

take a look at this thread: https://clojurians.slack.com/archives/C053AK3F9/p1646820965857209?thread_ts=1646816986.120279&amp;cid=C053AK3F9 you can do ^{:doc (:doc (meta #'clojure.pprint/pprint))} to keep the docstring

zackteo03:03:01

May I know how do y'all work with monorepos when you want to have different versions for different components. And how would git tagging work with that? Or do yall just have various repos

hiredman04:03:09

You don't, the version used is the version checked out

hiredman04:03:19

Dependencies inside the monorepo are not versioned

zackteo06:03:36

so there's not really an idea of cutting a release per se?

seancorfield06:03:20

External artifacts that you build can be released with versions, but inside the monorepo, the whole point is to avoid version dependencies and have the entire codebase stay in sync.

zackteo07:03:35

I'm still quite confused - is there some resource i could read?

zackteo10:03:31

Understand that Google uses a monorepo. I guess I'm really just trying to figure out what can solve my boss' version problem in a monorepo. Like he doesn't want to bump the version of something somewhat external to the main project when we bump the version of the main stuff. Does that mean this should be an external artifact? :o

dgb2310:03:38

I only started to look into this recently. But given your question it sounds like you have “somewhat of a monorepo”, or that the external thing is not really external or that it has too many responsibilities? If not you could use it as an external artifact or just maintain it from the monorepo. But bumping the version of an external thing seems like there are issues to be resolved first, maybe the “somewhat external” thing should be two things? In terms of git and tags: the article I linked discusses how they version control. It’s a very simple system without long-lived branches that merge back to main. It assumes that you have a single versioned main branch with feature flags on top and cherry-picking into release branches if so necessary. You can simplify it further and just use release tags instead of branches (that’s what we do).

dgb2311:03:05

(“we” as in small web shop so YMMV)

dgb2311:03:15

I think of the monorepo/trunk based version control as a kind of RDBMS with transactions that have the full view of a thing.

zackteo11:03:22

Perhaps I can distil it as the external part will end up functioning as a very small microservice. Something like a kafka message reader with an alert email system. Have a main project that is somewhat like a monorepo. And felt that instead of creating a separate project. I could just put it on the monorepo that we have. But in a sense they are 2 separate projects with different versions since. I wouldn't want changes in my alert stuff to bump the version of the main project vice versa

zackteo11:03:45

Maybe what I want is an external artifact. Not really sure how that works :thinking_face:

zackteo11:03:09

Any resources I can look to explain how that works? :o

mpenet12:03:33

there's a middleground:

mpenet12:03:53

I think having a bunch of deps versions in sync is great, but you don't want to rebuild your entire fleet of services for every bump

mpenet12:03:14

most of the times you dont have to. But knowing what version of a thing works with another has value

mpenet12:03:47

personally I was toying with the idea of having the dependency "manifest" for all versions of all deps for all services under version control and allow services to depend on it somehow (via stg like a git submodule). So you have a way to choose when to "re-sync", while having at least the guarantee stuff that worked together at a time would always be the same

mpenet12:03:16

it's an odd situation, in that case we cannot/don't want to go monorepo, we have plenty of multi-modules repo tho

mpenet12:03:28

also no tools.deps in that context

mpenet12:03:20

but if I could choose I think I'd go the monorepo route. But it's a lot of work to port to it in this case

mpenet12:03:21

and use tools.deps of course

zackteo13:03:29

Any guides to get started on tools deps when i have pretty much always been using lein? (I also need guides on converting the :release-tasks part but that's later on i guess)

zhuxun206:03:29

Is there a way to obtain a persistent copy of a transient value without making the original transient persistent?

jaide06:03:00

Would it be possible to get the value of a transient on the 1000th entry and reset! an atom then have a watcher on the atom to react to it?

zhuxun206:03:35

@U8WFYMFRU But the question remains: when I finally call the (report ...) I have to pass the value of the transient, but report expects persistent

jaide06:03:12

Could you deref it to get the value?

zhuxun206:03:54

deref the atom? What's in the atom? Isn't it the transient again?

jaide06:03:45

Was thinking you could deref the transient

lilactown15:03:32

@U8WFYMFRU you might be thinking of volatile. transients don't implement IDeref

lilactown15:03:43

@U6SEJ4ZUH you could iterate over the values/entries of the persistent collection and create a new persistent collection from them. however, I think you are going to miss out on any perf gains you are gettin from transients by doing this

lilactown15:03:25

is there a reason you are using transients in the first place? perhaps you could use a persistent data structure from the start

zhuxun215:03:53

@U4YGF4NGM I used transient because it's a tight loop that appends an element to a vector at every iteration. Though I haven't measured if there's any the performance gain doing that...

jaide15:03:56

Oh right that may be what I was thinking of

zhuxun206:03:52

I needed this because the transient is in a tight loop but I want to periodically (e.g., every 1,000 iterations) make a report based on what's currently in the transient, but I don't want to pass a transient to the report function which expects a persistent

andy.fingerhut06:03:56

If it is only every 1000th iteration or so, i.e. occasionally, you could simply create a persistent value from the transient, call the function that needs a persistent, then create a new transient from that and continue, yes?

👍 1
andy.fingerhut06:03:18

If it is only occasionally, I would not expect that to cause much of a performance hit at all.

jumar08:03:40

Btw. Did you measure the actual performance of the loop when not using transients vs using them? What's the difference?

jaide06:03:12

Is there a core function for performing a filter like operation but short-circuiting when an coll item first passes the predicate?

jaide06:03:21

Transducers are not my favorite but seems like it would do the job, thanks.

vemv06:03:52

I'd reduce over the coll and call reduced when I find the thing

jaide06:03:31

Some would totally do the job, thank you!

seancorfield06:03:35

(some #(when (predicate %) %) coll) sounds like what you want...

💯 2
jumar08:03:43

If you are willing to add a library, I always use medley.core/find-first for that. (it also seems to be significantly faster than some)

jaide08:03:55

Good to know, I'll have to learn how it's implemented

simongray12:03:30

I wonder why you can’t unquote using ~ inside a regular quoted data literal?

delaguardo12:03:35

~ is defined only within syntax quote literal `

delaguardo12:03:14

could you explain more the usecase you thinking about?

simongray12:03:13

The use case is populating all of the data literal templates in use all over Clojure, e.g. for querying Asami I currently have to do this:

[:find '?id '?sort-value
 :where
 ['?e :db/ident '?id]
 ['?e sort-key '?sort-value]]
rather than this:
'[:find ?id ?sort-value
  :where
  [?e :db/ident ?id]
  [?e ~sort-key ?sort-value]]
i.e. I have to quote every single symbol as opposed to quoting the outer data structure + unquoting a single symbol

simongray12:03:31

these data-oriented DSLs are so common in Clojure

Alex Miller (Clojure team)13:03:03

clojure.template can sometimes help with these

Alex Miller (Clojure team)13:03:41

Most people aren’t aware that's even in core

delaguardo13:03:04

I was about to suggest the same 🙂 thanks Alex

simongray12:03:17

Seems like a really useful feature to have…

Takis_15:03:53

hello, i am trying to deploy on clojars and i am getting Read timed out my jar is (7968k)

Takis_15:03:15

i upload like 1mb/sec but still, timeouts in like 5 sec

Takis_15:03:03

i used lein deploy clojars and given username/token , i uploaded the jars of 3 projects only one timeouts

Takis_15:03:36

i dont know why the jar is so big, for some reason it has the dependencies also, for example from the 8mb the 6mb is clojure

Takis_15:03:02

the other 2 jars are so small like kb, and they dont have the dependencies, but i didnt do anything different, in all i just did lein deploy clojars

lilactown15:03:43

sounds like an issue with your lein config

Takis_15:03:22

i reinstalled lein, and its the same, its a mixed java/clj project , for some reason it looks like it only produces standalone jar

noisesmith15:03:03

this would be project config not the config for lein itself. can you share your project.clj? do you have aot turned on by chance?

Takis_15:03:49

i comments one aot just now

Takis_15:03:31

that was it, thank you for your time

anonimitoraf22:03:57

Hi guys, any ideas why lein classpath returns something like

$ lein classpath
/home/anonimito/work/audience-republic/server-4/.cpcache/21FA38690A160741FD2BB36A1C13039C.jar
as opposed to a list of paths? FWIW, to verify that it's not a clojure deps.edn (i.e. non-lein) project
$ clojure -Spath
src:/home/anonimito/.m2/repository/org/clojure/clojure/1.10.3/clojure-1.10.3.jar:/home/anonimito/.m2/repository/org/clojure/core.specs.alpha/0.2.56/core.specs.alpha-0.2.56.jar:/home/anonimito/.m2/repository/org/clojure/spec.alpha/0.2.194/spec.alpha-0.2.194.jar
versions
$ lein --version
Leiningen 2.9.8 on Java 11.0.15 OpenJDK 64-Bit Server VM

hiredman22:03:39

likely some kind of plugin

lukasz22:03:24

worth checking if lein do clean, classpath helps

hiredman22:03:35

returning anything in .cpcache as the classpath is weird, because .cpcache doesn't contain code or jar files, it contains files that contain classpaths

hiredman22:03:43

lein does (did?) support writing a classpath to .classpath which if I recall would override the projects classpath