clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
chouser 2021-06-04T05:32:12.357400Z

Thanks, all! I should have mentioned I'd found the community link, but wasn't sure how vetted or up to date it is.

Arjaz 2021-06-04T08:25:13.357800Z

Hi, does anyone know if and how I can extract a list of all required namespaces from a given namespace programmatically in Clojure?

Arjaz 2021-06-04T08:25:29.357900Z

Something like the following:

(ns-requires *ns*) ;; => [clojure.set clojure.string]

borkdude 2021-06-04T08:27:57.358500Z

@art6661322 a namespace is either already loaded or it is not, but it doesn't matter which namespace did this, so this information isn't saved anywhere I believe. you can inspect the aliases that are valid within a namespace

borkdude 2021-06-04T08:29:10.358800Z

This can give you some info:

user=> (binding [clojure.core/*loading-verbosely* true] (require '[clojure.set] :reload))
(clojure.core/load "/clojure/set")
nil

Arjaz 2021-06-04T08:30:56.359200Z

Thanks for the help. I'm trying to solve a problem where I want to test if the given namespace loads the proper list, so I can have lein test signal if something weird is going on. We're using a bit of dynamic namespace parsing, so it really matters for us which namespace loads what

borkdude 2021-06-04T08:31:55.359400Z

for testing you could use with-redefs on require

borkdude 2021-06-04T08:32:51.359600Z

user=> (with-redefs [require (fn [& args] (prn :req args))] (require 'clojure.set))
:req (clojure.set)
nil

thheller 2021-06-04T08:33:07.359800Z

(ns-aliases (find-ns 'foo.bar))

borkdude 2021-06-04T08:33:49.360100Z

@thheller that's not sufficient here:

user=> (require '[clojure.set])
nil
user=> (ns-aliases *ns*)
{}

thheller 2021-06-04T08:34:38.360300Z

true, it is not 100%. most of the time things will have :as aliases though so should be good enough

Arjaz 2021-06-04T08:36:17.360600Z

Not for my case, unfortunately

borkdude 2021-06-04T08:37:35.360800Z

What you can also do as a test is, require a namespace and test if after doing that, the other namespaces have been loaded?

thheller 2021-06-04T08:37:56.361100Z

hmm yeah then it gets tricky, especially if there are some namespaces that are AOT compiled since those won't show up in regular require logs

borkdude 2021-06-04T08:38:41.361300Z

unless you temporarily re-define require using with-redefs

thheller 2021-06-04T08:39:25.361500Z

once it enters AOT loading it won't use require anymore so redef does nothing

Arjaz 2021-06-04T08:40:08.361700Z

I think I can parse out the require list or go with the with-redefs solution

borkdude 2021-06-04T08:40:30.361900Z

true

caumond 2021-06-04T08:46:29.364700Z

Hi, following my previous post. I re-did evaluations with criterium. 16ns for the java method, vs 64ns for the native clojure one. Is there any reason why clojure does not implement rand-intthat way ? https://gist.github.com/a30660391c68255e65ff60970e706c22

borkdude 2021-06-04T08:47:46.365Z

@caumond consider using a gist for long code fragments

borkdude 2021-06-04T08:48:52.365600Z

I think this would be a good question for http://ask.clojure.org as well

nbardiuk 2021-06-04T08:53:34.365800Z

Try to benchmark java version when you create seed each time. Notice that clojure version probably allocates it since it is not an input argument

caumond 2021-06-04T08:54:06.366Z

ok, I'm just trying to learn what a gist is first, (;p

borkdude 2021-06-04T08:54:49.366200Z

or pastebin :)

caumond 2021-06-04T08:56:12.366600Z

I did it !

borkdude 2021-06-04T08:57:49.366800Z

yay :)

caumond 2021-06-04T08:58:13.367Z

Seed is expected to be done once ! If I re-init seed each time, I'll have always the same result

caumond 2021-06-04T09:13:53.367300Z

And I followed the question to http://ask.clojure.org following your recommandation. Thx.

hanDerPeder 2021-06-04T09:53:50.371200Z

Procrastination alert! I can implement this operation

[{:key :foo :value 1} {:key :bar :value 2}] => {:foo 1, :bar 2}
like this
(reduce #(assoc %1 (:key %2) (:value %2)) {} coll)
or maybe
(into {} (map (juxt :key :value) coll))
but not really happy with either. Any ideas?

2021-06-04T10:00:02.371300Z

last one is good except it could be in transducer form:

(into {} (map (juxt :key :value)) coll)

☝️ 1
2021-06-04T10:00:14.371500Z

what do you think is wrong with it?

roklenarcic 2021-06-04T10:06:43.372900Z

I have a data reader #object defined. This works:

(def x #object[org.joda.time.DateTime 0x3ff80a66 "2021-07-04T09:54:54.937Z"])
but this doesn’t
(identity #object[org.joda.time.DateTime 0x3ff80a66 "2021-07-04T09:54:54.937Z"])
Why is that?

hanDerPeder 2021-06-04T10:27:09.373200Z

not sure. i think it has something todo with the fact this the expression is saying ‘add this value under this key’, but in my head i’m thinking ‘add as this key’. i suppose (juxt :key identity) would express that. thanks!

2021-06-04T10:57:54.375200Z

I’ve just type hinted the return value of a protocol function with a class. It’s a common pattern in our code to call this function inside a with-open. However it seems this is strictly speaking a breaking change, because consuming namespaces now need to import the class that the type hint relates to, is that right?!

2021-06-04T11:00:50.375800Z

I know get compile errors at call sites that call (with-open [(myprotocol/open-the-thing ,,,)] ,,,)

alexmiller 2021-06-04T12:05:58.378100Z

What does #object read into ?

alexmiller 2021-06-04T12:12:31.378700Z

I don’t know why. Why does it matter?

caumond 2021-06-04T13:05:14.378900Z

Sorry @alexmiller I don't understand. Why the performance is important? the seed?

alexmiller 2021-06-04T13:10:13.379500Z

What's the reason behind the whole thread?

2021-06-04T13:11:24.380200Z

I know about this article that advocates for passing system as a first argument for a protocol impl: https://puredanger.github.io/tech.puredanger.com/2014/01/03/clojure-dependency-injection/

2021-06-04T13:11:48.380800Z

There's some other article that says this for functions that does IO?

2021-06-04T13:12:48.382Z

To make your IO execution to not depend on global variables and to pass the dependency in a explicit way (a.k.a. as a first argument of a function)

2021-06-04T13:15:12.383500Z

I've been programming a lot in this way since I began on Clojure and "it just felt right", how can I explain that it gets your code better more than simply saying that It's easier to debug / It's easier to mock?

borkdude 2021-06-04T13:23:13.383900Z

@d.ian.b do you mean passing the component system as the first arg?

2021-06-04T13:24:23.385300Z

Yeah, some form as component system, can be a map of system stuff (as right now I'm using https://github.com/piotr-yuxuan/closeable-map to make the system component)

borkdude 2021-06-04T13:24:29.385600Z

Note that component itself discourages it: https://github.com/stuartsierra/component#do-not-pass-the-system-around

borkdude 2021-06-04T13:25:04.386400Z

(although I have to admit that this is quite a common pattern in the codebase I'm working on 😅 )

2021-06-04T13:28:47.389700Z

yeah, but right now I'm not using component itself, if I have to make IO to a database I can do something like

(defn my-insertion-db! [{::config/keys [datasource]} data]
  (log "some data!" (pr-str data))
  (->> data
       some-transformation
       (jdbc/execute! datasource))

2021-06-04T13:30:02.391300Z

and for testing I can do something like

(with-open [system (-> config make-dev-system!)]
  (my-insertion-db! system data))

borkdude 2021-06-04T13:30:06.391400Z

it's basically the same thing, just a data structure with components

2021-06-04T13:31:25.392600Z

No function should take the entire system as an argument => I know that sometimes you would prefer to pass part of the system (the part that your IO needs to use to handle it) as the argument of your function

2021-06-04T13:31:47.393100Z

but destructuring seems to fit very well for these stuff

2021-06-04T13:33:20.395Z

but the thing I don't like is to have the system as a global variable (people are arguing that we need to make functions that has global vars embedded and returns a function that does the IO, because is simple to mock using with-redefs)

✅ 1
borkdude 2021-06-04T13:33:42.395400Z

I agree, pass arguments in favor of globals

2021-06-04T13:34:25.396200Z

because polutes functions to pass around system for every stuff (I've said not every stuff, just IO stuff haha)

2021-06-04T13:38:14.397200Z

I think is more simple / clean to have just a map 😄

2021-06-04T13:42:02.397500Z

the idea is that instead of my-insertion-db receiving system it receives the datasource itself?

borkdude 2021-06-04T13:43:27.397900Z

yes

borkdude 2021-06-04T13:43:33.398100Z

only what the function needs I guess

👍 1
borkdude 2021-06-04T13:43:40.398300Z

but this is just an opinion, do what you want

1
marciol 2021-06-04T13:46:28.398500Z

Just the public APIs generally needs the system-map, other private functions downstream generaly will get only what it needs

caumond 2021-06-04T13:46:54.398700Z

1. I feel like a newbie so I may have done something fundamentally wrong 2. If that implementation is quicker and equivalent (what I think), it may be an improvement, something like :

(def ^java.util.Random seed (java.util.Random.))

(defn rand-int-alternative
  "Returns a random integer between 0 (inclusive) and n (exclusive)."
  {:added "1.0"
   :static true}
  [n] (.nextInt seed n))

marciol 2021-06-04T13:47:12.398900Z

Ahhh, I guess that it happens because destructuring a map is so easy 😄

2021-06-04T13:49:06.399400Z

yeah, I generally agree on pass only what the function needs, but destructuring helps a lot with this on most part of the time 😄

marciol 2021-06-04T13:50:18.400Z

> but destructuring seems to fit very well for these stuff Exactly!

alexmiller 2021-06-04T13:51:53.400200Z

as the author, I think "advocates" is a strong description - this is an idea, it may be useful, or it may not :)

👍 2
2
caumond 2021-06-04T13:54:13.400500Z

If you need more context I am trying to port an operations research tool I built years ago in C++. That kind of algorithms are combinatorial optimization, with a huge number of iterations on int-array. I start with some benchmarking between java and clojure and find out the global execution time gap was due to that rand-intfunction. That kind of use case are demanding from a time execution prospective (billion of iterations are expected).

2021-06-04T13:55:05.400700Z

I'm struggling to find this on clojure 😞, it has for Elixir though https://dashbit.co/blog/mocks-and-explicit-contracts

alexmiller 2021-06-04T13:56:38.401700Z

thanks, that was the context I was looking for. I don't think anything is preventing you from using your alternative method. I don't know why it's implemented the way it is. I'll make a ticket out of it when I get a chance.

jmckitrick 2021-06-04T14:08:06.403500Z

I'm trying to use Apache Tika to detect a file type. I'm getting some reflection errors I can't seem to figure out, and I haven't done much Java interop prior to this. Here's what I have:

jmckitrick 2021-06-04T14:08:08.403800Z

(with-open [xin (<http://clojure.java.io/input-stream|clojure.java.io/input-stream> (get-in params [:uploaded_file :bytes]))
                            tika (Tika.)
                            ftype (org.apache.tika.Tika/.detect tika)]
                  (prn "tika ----&gt;" ftype))

Andrew Lai 2021-06-04T14:08:47.404300Z

To your question about how to explain the value proposition of passing arguments vs. depending on globals: It sounds like you're trying to convince colleagues about the benefits of pure functions. Unfortunately, you'll probably have to tailor your arguments to your audience so your pitch will resonate with their specific experiences. Some arguments you could you could be: parallelization of tests - without global state you can safely parallelize your tests. transparency - global state is an additional, silent, side-channel input. It doesn't come through the front door like other function arguments. So the developer who picks up the test/code needs to know all of the relevant context to figure out how the function will behave. If you use pure functions and you know that the behavior only depends on the arguments supplied to the function, I've found it's much easier to understand and easier for other developers to understand.

1
jmckitrick 2021-06-04T14:09:21.405Z

So the first complaint is 'reference to field close can't be resolved' and then 'reference to field detect on org.apache.tika.Tika can't be resolved'

jmckitrick 2021-06-04T14:09:47.405600Z

I assume this is either an import issue or a namespace issue

borkdude 2021-06-04T14:10:10.405800Z

(.detect tika)

jmckitrick 2021-06-04T14:11:13.406200Z

That was my first attempt, and I got: 'No matching field found: close for class org.apache.tika.Tika'

roklenarcic 2021-06-04T14:11:51.407Z

(defn joda-time-data-reader [[class-symbol _objid date-time-string :as value]]
  (if (= "org.joda.time.DateTime" (name class-symbol))
    (tf/parse date-time-string)
    (throw (ex-info "Unsupported #object instance" {:value value}))))
So this should be a jodatime instance

jmckitrick 2021-06-04T14:11:54.407300Z

I'm conflating 2 issues, probably because I tried a plain 'let' in place of 'with-open' to see if I could get past the 'close' error

borkdude 2021-06-04T14:11:57.407500Z

this is because you have this object in your with-open

roklenarcic 2021-06-04T14:12:02.407600Z

org.joda.time.Datetime

alexmiller 2021-06-04T14:12:14.407800Z

in what way does it "not work" ?

borkdude 2021-06-04T14:12:27.408200Z

bindings in with-open are called with close at the end

roklenarcic 2021-06-04T14:14:54.408300Z

When I put

(def x #object[org.joda.time.DateTime 0x3ff80a66 "2021-07-04T09:54:54.937Z"])
in namespace code and load the namespace in a REPL, the value of X is as expected. But if I do something like:
(defn y [] #object[org.joda.time.DateTime 0x3ff80a66 "2021-07-04T09:54:54.937Z"])
and load that namespace I get:
Syntax error compiling fn* at (src/.../plans/presentation.clj:324:1).
Can't embed object in code, maybe print-dup not defined: 2021-07-04T09:54:54.937Z

jmckitrick 2021-06-04T14:15:23.408600Z

Oh, silly me. A separate 'let'

roklenarcic 2021-06-04T14:15:48.408700Z

Similarly if I just put like (identity #object….) in namespace top-level and try to load it, same error

caumond 2021-06-04T14:15:58.408900Z

yes, I agree this is not a critical issue. Thanks for your confirmation to use the 'alternative method'. It's all what I need.

roklenarcic 2021-06-04T14:16:58.409100Z

seems odd that def parses differently than other expressions

jmckitrick 2021-06-04T14:17:22.409500Z

And now it cannot resolve the 'detect'...

jmckitrick 2021-06-04T14:17:52.409900Z

Which is why I tried the full namespace... let's try that again...

jmckitrick 2021-06-04T14:19:34.410400Z

Hmm. So the 'close' is resolved, but not 'detect'

borkdude 2021-06-04T14:21:46.410800Z

just try it one expression at a time

jmckitrick 2021-06-04T14:23:11.411Z

Got it!

jmckitrick 2021-06-04T14:23:20.411300Z

(.detect tika xin)

jmckitrick 2021-06-04T14:24:05.411500Z

Thanks, @borkdude

👍 1
alexmiller 2021-06-04T14:24:39.411600Z

right, so the data reader is reading into an object. that object can't be represented in bytecode as a value, so you can't compile the function like that. def is different case

alexmiller 2021-06-04T14:25:58.412Z

you can probably add a printer for this type of object though and get it to work

alexmiller 2021-06-04T14:26:13.412200Z

you do that by extending the print-method and print-dup multimethods

alexmiller 2021-06-04T14:26:43.412400Z

you then have roundtripping of read/print which are complementary operations

roklenarcic 2021-06-04T14:33:25.412600Z

I see, thank you

2021-06-04T14:48:05.412900Z

Also if you define a print operation for these values, then it would be preferable for the reader to not read #object, but rather read something like #joda/datetime

alexmiller 2021-06-04T14:48:21.413100Z

for sure

2021-06-04T14:48:28.413300Z

This will prevent issues with other objects being read as date times.

dominicm 2021-06-04T15:09:10.414800Z

Does anyone know a file-system backed TTL cache? I'm communicating with an API with limits with a process that will stop/start on my machine. I've not found a java thing surprisingly!

2021-06-04T15:16:26.415300Z

@dominicm Do you mean for http caching, etags etc?

dominicm 2021-06-04T15:25:33.416400Z

@rickmoynihan I can hit an api 20 times a day, and I only want to do that every hour to make sure I don't deplete that. I want to make sure while I'm developing I don't deplete it either by restarting my jvm a few times.

2021-06-04T15:26:02.416800Z

something like https://github.com/oliyh/martian/tree/master/vcr ?

2021-06-04T15:26:56.417300Z

There are some other similar projects “vcr” will probably help you mind them.

dominicm 2021-06-04T15:27:52.417800Z

@rickmoynihan vcr is more about testing. I am looking for something that expires after 1 hour, and to fetch a new one when that happens.

borkdude 2021-06-04T15:28:52.418Z

redis?

dominicm 2021-06-04T15:29:15.418500Z

A filesystem would be great, this project will have no other dbs or anything.

borkdude 2021-06-04T15:29:43.419Z

postgres with a timestamp column?

borkdude 2021-06-04T15:30:05.419400Z

or sqlite for that matter

2021-06-04T15:30:17.419900Z

could you use varnish as a proxy?

dominicm 2021-06-04T15:30:25.420200Z

@borkdude I mean, if I'm gonna roll my own I'll probably just use duragent and the local-file thing 😛

borkdude 2021-06-04T15:30:45.420500Z

yeah, it doesn't seem that much work to be honest

dominicm 2021-06-04T15:34:31.421Z

Feels like one of those obvious things though, I thought it would already exist.

Helins 2021-06-04T15:37:20.422900Z

I am not sure I understand why it works: ns A has a macro that outputs a call to another macro from ns B ; ns C calls that macro but does not require ns B ; all is cool

(defmacro macro-a [x] `(B/macro-b ~x))

borkdude 2021-06-04T15:38:26.423300Z

just use macroexpand to see what happens?

2021-06-04T15:38:34.423400Z

when macro-a expands it will make the symbol B/macro-b fully qualified

2021-06-04T15:39:11.423600Z

and if the namespace with that symbol is loaded by any other namespace it will be resolved correctly

Helins 2021-06-04T15:45:14.423800Z

Right, I might have been confused on that last point in my CLJC project. Indeed, ns B was being loaded in Clojure but not in CLJS, so it was misbehaving in CLJS. Make sense!

2021-06-04T16:21:44.424800Z

Just being lazy instead of translating this but anyone know of a clojure bigdec natural log implementation in the wild, like this java one https://stackoverflow.com/questions/739532/logarithm-of-a-bigdecimal

dpsutton 2021-06-04T16:39:52.425Z

this relation seems really handy: log(AB) = log(A) + log(B). This might get into things like numerical stability and errors related to that

quoll 2021-06-04T17:07:44.425200Z

That relation is how slide rules work

2021-06-04T17:40:17.425500Z

(juxt :key idenity) creates a different output though

Michael Gardner 2021-06-04T17:40:54.425700Z

whenever I find myself writing (juxt ... identity) I reach for Medley's index-by

Nom Nom Mousse 2021-06-04T18:14:54.427300Z

Is there a way to have the std{out,err} from shell/sh sent somewhere in real-time? Now I only get :out and :err info after the job is done 🙂

Endre Bakken Stovner 2021-06-07T14:58:18.045300Z

@borkdude I guess there should be a (when (not (nil? line)) (recur)) above?

Endre Bakken Stovner 2021-06-07T14:59:01.045500Z

I tried it and it just keeps on printing :line nil forever 🙂

borkdude 2021-06-07T15:00:12.045700Z

@endrebak85 you are correct, but the output from yes never ends :)

Endre Bakken Stovner 2021-06-07T15:01:26.045900Z

♾️

2021-06-04T18:16:05.427400Z

I believe Java ProcessBuilder class can enable you to do that. I don't think that the built-in-to-Clojure shell/sh can do that.

borkdude 2021-06-04T18:16:37.428200Z

@endrebak With babashka.process (https://github.com/babashka/process) this is very easy:

@(babashka.process/process ["ls"] {:inherit true})

2021-06-04T18:18:51.428900Z

yeah I have a snippet doing that with ProcessBuilder:

(let [pb (ProcessBuilder. ["lua"])
      p (.start pb)
      out (.getOutputStream p)
      in (.getInputStream p)]
  (spit out "print \"hello from lua\"\n")
  (slurp in))
very straightforward, compared to most java apis

2021-06-04T18:19:29.429200Z

of course for real interactivity you have to use something other than slurp / spit (and that means more complexity) - I'm sure there's some good libs that simplify that streaming IO stuff out there

2021-06-04T18:20:48.429800Z

sounds like you want the stdout / stderr for monitoring? you should be able to .read from the output stream and error stream in a loop and trigger a callback for each line / chunk / whatever

2021-06-04T18:22:12.430800Z

you can also use processbuilder to stream to a file or pipe instead of a stream, and to join the streams if that simplifies your use case as well

2021-06-04T18:23:46.432700Z

and vanilla clojure / interop version of the same:

(doto (ProcessBuilder. ["ls"]) (.inheritIO) (.start))

🙏 1
Nom Nom Mousse 2021-06-04T18:23:50.432900Z

Cool! I'll have to look more into babashka. But let's say I have multiple processes running at the same time in futures. Can each of them send data to a tap or something with inherit? So I get messages like:

jobid1 :stdout "message from job1"
jobid3 :stderr "this job failed"
... 
I will have to play around with :inherit to understand how it works.

2021-06-04T18:24:22.433700Z

inherit just sends to *out* and *err*- see my reply in the other thread for using the streams with a callback

borkdude 2021-06-04T18:24:42.434200Z

inherit doesn't send to *out*, it sends to System/out

2021-06-04T18:25:05.434400Z

oh, good catch

Nom Nom Mousse 2021-06-04T18:25:11.434500Z

Thanks to both of you 🙂

Nom Nom Mousse 2021-06-04T18:27:27.434700Z

I am using my software to run multiple (shell) jobs concurrently and want output from them ASAP and continually so I can see if anything goes wrong. So yes, I guess monitoring is the word.

borkdude 2021-06-04T18:28:58.434900Z

@endrebak Example with babashka.process (which you can use as a regular Clojure library):

(require '[babashka.process :refer [process]])
(process ["foo"] {:inherit true})
(process ["bar"] {:inherit true})
.. wait .. e.g. @(promise)

👍 1
2021-06-04T18:29:29.435100Z

they mentioned they don't want the output to go to stdio of the repl

borkdude 2021-06-04T18:29:52.435300Z

> and want output from them ASAP and continually so I can see if anything goes wrong oh, I thought he/she/they did say that here

Nom Nom Mousse 2021-06-04T18:31:37.435700Z

But if multiple jobs send to stdout concurrently they might overlap. Also, I want to send some to the front-end and so on so it would be best to send it to a tap or something 🙂

borkdude 2021-06-04T18:32:07.436Z

just make a loop that reads the output line by line, prints it and does whatever else with it

🙏 1
Nom Nom Mousse 2021-06-04T18:32:33.436300Z

This is all new to me. Sounds like it is not that hard then. Thanks!

borkdude 2021-06-04T18:34:10.436500Z

I have a similar example to that here: https://book.babashka.org/#child_processes

borkdude 2021-06-04T18:37:35.436800Z

Here is a simple example that reads the output from yes:

(require '[babashka.process :as p :refer [process]]
         '[<http://clojure.java.io|clojure.java.io> :as io])

(def yes (process ["yes"] {:err :inherit
                           :shutdown p/destroy}))

(with-open [rdr (io/reader (:out yes))]
  (binding [*in* rdr]
    (loop []
      (let [line (read-line)]
        (println :line line))
      (recur))))

2021-06-04T22:27:33.438400Z

why does evaluating an empty anonymous function using the #() syntax yield an empty list? I expected... maybe nil?

user=&gt; (#())
()
user=&gt; ((fn []))
nil

dpsutton 2021-06-04T22:30:41.439200Z

See what the reader returns. ‘#()

Felipe 2021-06-04T22:39:33.440900Z

I see! nice!

dpsutton 2021-06-04T22:39:49.441500Z

Learned that one from noisesmith.

Joel 2021-06-04T22:48:27.443500Z

is reducing a list of maps a bad idea? I'm trying to write a reducer function, but it seem problematic. I want string values to turn into a list of strings, list values to be a flattened list, but picking the right incantation (concat cons conj, etc.) seems challenging.

emccue 2021-06-04T22:59:52.443800Z

@joel380 when in doubt, loop it out

emccue 2021-06-04T23:00:33.444600Z

skip all them helpers and just write a big ol' loop and recur

dpsutton 2021-06-04T23:19:40.445600Z

A transducer with a mapcat would work a treat on that