Fork me on GitHub
#clojure
<
2019-12-05
>
sogaiu00:12:35

is there a convenient way to determine which source files get pulled in during a call to (compile my-ns)?

noisesmith00:12:49

@sogaiu I think this dynamic var might help - the code that loads namespaces uses it to decide whether to print

user=> (doc clojure.core/*loading-verbosely*)
-------------------------
clojure.core/*loading-verbosely*
  True while a verbose load is pending

sogaiu00:12:22

thanks! i'll give that a try

sogaiu00:12:11

@noisesmith that was helpful, thanks!

Eduardo Mata01:12:35

how could I spit an edn and have it pprinted ?

noisesmith01:12:14

pprint takes an optional writer arg, or you can use with-out-str to create a string out of what would otherwise be printed, and then write that

noisesmith01:12:52

@contact904

(ins)user=> (with-open [w (io/writer "foo.edn")] (pprint {:a 0 :b 1 :c (range 12) :d (zipmap (range 10) (range))} w))
nil
(cmd)user=> (println (slurp "foo.edn"))
{:a 0,
 :b 1,
 :c (0 1 2 3 4 5 6 7 8 9 10 11),
 :d {0 0, 7 7, 1 1, 4 4, 6 6, 3 3, 2 2, 9 9, 5 5, 8 8}}

nil
• edit - removed redundant io/file call that io/writer doesn't need, a writer should use with-open

❤️ 4
noisesmith01:12:36

with-out-str effectively does the same thing

(ins)user=> (spit "bar.edn" (with-out-str (pprint {:a 0 :b 1 :c (range 12) :d (zipmap (range 10) (range))})))
nil
(ins)user=> (= (slurp "foo.edn") (slurp "bar.edn"))
true

noisesmith01:12:15

funny enough, nearly identical character count between the approaches

dpsutton01:12:21

Didn’t know about the extra output. Thanks!

noisesmith01:12:09

I wouldn't know it took a writer arg, except for the error you get when you pass two clojure data objects to one pprint call (hey, it works with println...)

noisesmith01:12:12

the version without the with-open worked accidentally thanks to the writer's finalizer since it fell out of scope instantly, but the correct way is to use with-open, so I fixed it

wei01:12:14

is there an appropriate channel to announce projects?

sogaiu01:12:50

#announcements ?

👍 4
Eduardo Mata02:12:48

I have build a jar file. However, when I run it with java -jar I get in return an error telling me that one of my functions does not exists! But it exists. If I run it in the repl, It works 100%

Eduardo Mata02:12:18

Caused by: java.lang.RuntimeException: No such var: elastic/search-hits

Eduardo Mata02:12:15

I can even run my project in the repl directly in the namespace where the exception is coming from and run the function with no problem

Eduardo Mata02:12:17

Eastwood, kibit, yagni, and bikeshed are coming back postive, with no erros

hiredman02:12:04

How are you building your uberjar?

Eduardo Mata02:12:27

it is kind of complicated. I am using boot and my own boot task.

Eduardo Mata02:12:37

I just deleted my boot cached and it work 😐

hiredman02:12:44

My off the cuff guess is you are calling eval somewhere and assuming that the value of *ns* is something it is not

Eduardo Mata03:12:14

It is weird becasue if I run the jar couple times in the row. the Error will go away

tundrax11:12:48

Hi. What is the most common deployment model for clojure web apps (servers)? Specifically, deployments when there are services like AWS ECS Fargate, does one really need Application Servers (containers) like Tomcat, Jetty etc.? Anyone using systemd + jvm + nginx sidecar deployment in production?

p-himik12:12:23

I use it. Only it's a single in-house server. 🙂 No clouds here.

papachan12:12:17

I just use a docker image with clojure installed there. we dont have any special configs. you dont benefit of an owner role thats all

tundrax12:12:07

Great, thanks. And, with the usual web service (app) involving RDBMS, is PostgreSQL a viable choice for Clojure?

p-himik12:12:49

I think it's the perfect choice for about 99% of scenarios. YMMV though.

tundrax12:12:10

It has been the primary choice for me and the tools I've used so far. I am just curious, maybe there are some core inconsistencies you may have encountered.

p-himik12:12:48

Not really inconsistencies - just an occasional need to map some type that some jdbc library didn't map itself. So far, has happened to me only once. Also, it depends on how you will create your queries. E.g. with honeysql and honeysql-postgres, I sometimes need to add a defmethod that describes some keyword that the libraries don't know about.

tundrax12:12:21

Nice. Btw, is Ring the de-facto framework? Can you serve using just stdlib?

p-himik12:12:54

I have no idea, I have never used Ring. I use Edge, which uses Yada, which uses Aleph.

p-himik12:12:34

Ah, no - I've used Ring once, for my very first Clojure project that was an entry project for some job. 🙂

p-himik12:12:41

Not at all.

tundrax12:12:38

For the ones coming from ruby, golang, nodejs - java terms and acronyms are just 😱

tundrax12:12:51

пойду рыть дальше

Mattias12:12:44

Examples of Java acronyms?

tundrax12:12:01

jstl, war, eej, servlets, server pages - some of those

p-himik12:12:23

To be honest, I only barely know what war means. 😄

p-himik12:12:47

The rest of them - no idea. It doesn't prevent me from writing software in Clojure.

tundrax12:12:21

i learned it today, it has to be web archive

p-himik12:12:39

There are plenty more acronyms and concepts in the JavaEE world. It doesn't mean you need even a single one of them to create something of value.

tundrax12:12:40

That confidence you have only after deploying, some production ready apps. But, for the beginners, we try to find the analogous tools and concepts.

tundrax12:12:20

So we can map, project our understanding to the new ecosystem.

tundrax12:12:46

Or is it just me, not sure.

p-himik12:12:59

The best advice out there in this situation is probably "just go do it". 🙂 Not "just deploy something to production" of course, but "just create a working web app and see for yourself". Try Ring, try Aleph, try raw CLJ, see what you like. Read a bit about them, create some more. Yet another kind of loop, not unlike REPL.

👍 4
borkdude12:12:42

user=> (Character/isWhitespace (char 65279))
false
😕

😑 4
p-himik12:12:32

From https://bugs.openjdk.java.net/browse/JDK-5039533 "The static function java.lang.Character.isWhitespace(char ch) correctly recognizes U+00A0, U+180E, U+202F, U+2060, U+FEFF as non-breaking spaces and excludes them from being considered whitespaces according to the documentation and specifications." Not sure why though.

borkdude12:12:45

Postgres choked on it when inserting XML: XML declaration allowed only at the start of the document

p-himik12:12:21

Ooof, that error still haunts me, although for a different reason.

dabrazhe13:12:34

Hi. I am getting reflections warnings call to method indexOf can't be resolved (target class is unknown) The function params are a regex string and a sequence (vector of strings\n), it's returning index of the first occurrence of sub-string in seq. Is there a way to resolve the warning?

(defn firstindexof [timestap seqq]
           (.indexOf seqq
            (first
             (filter #(re-find timestap %) seqq))))

holyjak13:12:11

I guess

(defn firstindexof [timestap seqq]
           (.indexOf seqq
            ^String
            (first
             (filter #(re-find timestap %) seqq))))

dabrazhe13:12:32

Not,really( still complaining

p-himik14:12:36

I think it doesn't know about the seqq type - try adding a type annotation for it.

dabrazhe15:12:18

it's a sequence of strings, or rather a sequence returned by (line-seq reader). is there a way to annotate it by type?

p-himik15:12:27

(type (line-seq ...)) returns clojure.lang.Cons. Try using that. Although I find it strange that the type isn't known here. In what context do you get the reflection warning? I tried it in a REPL and don't see anything.

dabrazhe16:12:45

The warning happens when evaluating it in repl.

dabrazhe16:12:49

your advice helped, thanks!

(defn firstindexof [timestamp ^clojure.lang.Cons seqq]
  (.indexOf seqq
            (first
             (filter #(re-find timestamp %) seqq))))

p-himik17:12:04

Really interesting. Can you tell how you run your REPL? Because right now, the code will probably fail if you pass there anything but Cons. E.g. a vector.

dabrazhe17:12:31

yep )

Execution error (ClassCastException) at data-health.dataloss/firstindexof (form-init17101450020595890464.clj:1).
class clojure.lang.PersistentVector cannot be cast to class clojure.lang.ASeq (clojure.lang.PersistentVector and clojure.lang.ASeq are in unnamed module of loader 'app')

p-himik17:12:32

Ah, you have (set! *warn-on-reflection* true). I didn't know about this option. It seems that you have 3 options: 1. Stop caring about reflection 2. Use a more wide-spread type annotation (e.g. just APersistentVector) and just wrap the argument each time you call the function (in vec) 3. Rethink the way you work with data - maybe there's a more idiomatic approach, as explained e.g. here: https://stackoverflow.com/a/4831170/564509

dabrazhe08:12:55

yes, the option on reflection is indeed set, I though you new about it, as your advice was spot on : ). I can choose to ignore it but it's interesting to see how can I solve in a proper way. I was thinking about something generic, like a collection etc that will accept set, vector, and list type

p-himik08:12:08

The issue is that all of the collections that implement .indexOf, implement it on its own and not as a part of some interface.

holyjak13:12:26

In JavaScript I can do text.replace(regExp, (m, grp) => grp.toUpperCase()) How can I replicate it in Clojure? The thing is that my replacements aren't static, I need to run a fn on the match. I could do it in two steps - 1) extract all matches, 2) create a map match -> replacement, 3) replace every match by the corresponding replacement one by one. But perhaps there is a nicer way?

4
dominicm13:12:08

Some of the clojure string functions take a function

dominicm13:12:41

Replace does, so you could use that?

Daniel Stephens13:12:43

(clojure.string/replace "some-text" #"some-regex" clojure.string/upper-case)

holyjak14:12:43

Awesome, how could I have overlooked that? Thanks a lot!

mourjo14:12:10

When shutdown-agents is called in Clojure, it stops both the agent threadpools (`soloExecutor` and pooledExecutor) but since future spawning happens on the soloExecutor, is there any way to say that I want the agents to stop but new futures can still be spawned? Without using something like a dedicated pool and spawning futures on it like with https://github.com/TheClimateCorporation/claypoole?

aisamu14:12:00

Would it be possible/useful to shutdown just the pooledExecutor? (i.e. (.shutdown clojure.lang.Agent/pooledExecutor))

alexmiller14:12:52

you should only call shutdown-agents if you are shutting down the jvm

mourjo14:12:55

@U1UQEM078 Thanks, I think that would work, I’ll try it out @U064X3EF3 I am calling shutdown-agents during JVM shutdown but there are a few other shutdown hooks that are causing the JVM to take more time to exit, and in the meantime, if some thread calls future, it gets rejected. I’m right now catching the rejected exception and running it in the calling thread.

celwell15:12:47

What is the most Clojure-friendly observability platform? (New Relic, Honeycomb, LightStep, etc.)

mping17:12:55

Let me know when you find out. We basically use which is to say we decorate fns manually for newrelic's sake

seancorfield18:12:22

Hadn't seen that before @U0MQW27QB -- nice! We rolled our our tracing with New Relic (I blogged about it years ago) but this is much nicer. @U0HJJF9A4 Happy to answer Qs about New Relic -- we've been using it for years.

alexmiller15:12:41

I certainly know of people doing both New Relic and Honeycomb with Clojure /cc @ghadi

borkdude16:12:59

(require '[clj-time.format :as f])
(def example-date "Sat, 02 Nov 2019 00:00:00 GMT")
(f/parse (f/formatter :rfc822) example-date) ;; malformed at GMT
is this a bug or it this date truly not rfc822?

hiredman16:12:38

There is no joda time formatter symbol that corresponds to the timezones allowed in a rfc822 date

borkdude16:12:14

Thanks. I'll try clojure.java-time

borkdude17:12:40

I must the the author of clojure.java-time has courage. He uses clojure in the library name and the core namespace is just "java-time"

borkdude17:12:47

single segmented

seancorfield18:12:03

Love that lib, hate that name/namespace 🙂

Ramon Rios17:12:31

Anyone familiar with Schema?

aisamu17:12:40

Probably, and there's also #schema

Ramon Rios17:12:36

I'll ask there. Thanks.

Eduardo Mata18:12:07

If I start a Thread such as (-> (Thread. function-name-here) (.start)) How could I stop it?

chilliams18:12:45

(let [thread (doto (Thread. fn)  (.start))]
(.interrupt thread))

chilliams18:12:58

i find myself reaching for doto more often than -> for java interop

Eduardo Mata18:12:15

yeah, I will probably do the same to avoid kibit linting yelling at me about this

noisesmith19:12:56

NB: the interrupt method doesn't stop a thread, it sets a flag that makes certain methods exit. This is cooperative and opt-in, and you should make sure any thread that needs to be interruptable calls a method that exits cleanly if the interrupted flag is set

noisesmith19:12:18

there's no way to safely stop a thread from the outside in the jvm, it's always voluntary

erwinrooijakkers20:12:18

Is there a way to generate all valid values for a spec?

bfabry20:12:11

no. (s/keys) is a spec that describes any map with any keys

seancorfield20:12:10

"all"? That could be an infinitely large set of values...

seancorfield20:12:44

You could use s/exercise to randomly generate as many valid values as you want tho'...

erwinrooijakkers20:12:08

Ah all is difficult because spec cannot be that smart

erwinrooijakkers20:12:20

Trying to solve Advent of Code day 4 using spec

erwinrooijakkers20:12:31

• It is a six-digit number. • The value is within the range given in your puzzle input. • Two adjacent digits are the same (like 22 in 1_22_345). • Going from left to right, the digits never decrease; they only ever increase or stay the same (like 111123 or 135679).

erwinrooijakkers20:12:34

How many possible

noisesmith20:12:17

sounds like you want logic programming https://github.com/clojure/core.logic - give constraints and the code returns some datum satisfying the constraints

noisesmith20:12:24

since you need every possible solution (or the count...), you might think about the most efficient way to generate unique numbers fitting the pattern

erwinrooijakkers20:12:00

Ah yes it’s logic programming.

erwinrooijakkers20:12:36

Although now you can generate it more smarter than a core.logic evaluator I guess

dpsutton20:12:43

I did that one in core logic if you’d like to compare when you’re done

dpsutton20:12:52

Don’t know if it’s idiomatic though

erwinrooijakkers20:12:53

I’ll check afterwards in #adventofcode 🙂

Risetto20:12:45

Is it possible to update a value in an atom, by it's index? For example changing the value of the 5th value in a list

dpsutton20:12:23

ignore the atom. its just a container. if you know how to update the 5th value in a list you can do it in an atom

Risetto20:12:22

but it has to be an atom for me to be able to update it, right?

dpsutton20:12:00

if you want to update a single reference, it needs to be some kind of mutable container. Not sure if that's your requirement though.

Risetto20:12:23

Yea I think that is what I want yea

andy.fingerhut20:12:26

An atom is a mutable container/box/pointer/reference, intended to point at an immutable value. Creating a new immutable value from an existing immutable value, you have most of the Clojure library to help you with, and is no different than starting with any immutable value and producing another one.

andy.fingerhut21:12:31

If the immutable value is inside of an atom, then the only way to change what immutable value the atom points to, is via a function for modifying an atom, typically swap!

dpsutton21:12:12

if you're new to functional programming a common pitfall is to think you need mutability and atoms much more than you might otherwise need. Not saying that's your case now but that's something to be aware of if you're a beginner (and apologies if you aren't.)

lilactown21:12:16

@olle142 you can create a new list with a new value at the 5th index by using assoc:

(assoc '(0 1 2 3 4 5 6) 4 10)
;; => '(0 1 2 3 10 5 6)

noisesmith23:12:49

user=> (assoc '(0 1 2 3 4 5 6) 4 10)
Execution error (ClassCastException) at user/eval293 (REPL:1).
clojure.lang.PersistentList cannot be cast to clojure.lang.Associative

noisesmith23:12:00

you must have been thinking of square brackets here?

lilactown23:12:55

yeah I made that comment below, was thinking of vectors

lilactown21:12:10

if you want to update an atom that contains the list, you can use swap!

hiredman21:12:10

that is not correct, you cannot do that in clojure

lilactown21:12:29

maybe I’m thinking of vectors. on mobile atm

Risetto21:12:05

@dpsutton Yea I'm not quite used to the immutable way of thinking yet. If I need to update a lot of items in a list, is it more efficient to use an atom or is it better to create new lists for it? (because that's how you want to do it in clojure, right?)

Risetto21:12:17

Really? I will try that out.

Risetto21:12:29

I don't have to use a list, I can make it into a vector instead if that's the case

lilactown21:12:34

it will create a new immutable data structure either way, @olle142. whether you use an atom or not

lilactown21:12:07

this is usually pretty efficient due to the way that the immutable data structures are implemented

Risetto21:12:00

Alright, then I should probably just do it that way instead.

anonimitoraf21:12:14

see Structural Sharing

Risetto21:12:16

I only really "need" atoms for state and stuff usually?

dpsutton21:12:03

I haven't provided a solution for you because there's a lot that can vary according to your requirements and assumptions. ie, what if there are fewer than 5 elements, what data type, how its used, etc

dpsutton21:12:13

also #beginners is a great place to hash these things out as you're getting used to the functional/immutable paradigm

Risetto21:12:13

Trying to use the assoc function on my list gives me a ClassCastException, which has to do with trying to redefine my constant or something?

dpsutton21:12:41

lists aren't associative. the suggestion above was incorrect. vectors are though

sogaiu21:12:28

in: http://www.duelinmarkers.com/2016/01/24/the-life-of-a-clojure-expression.html there is this bit:

If the form being eval‘d is not a “def” of some kind, it’s wrapped in a zero-arity fn and that fn is invoked. I don’t know why that’s necessary. (If you do, please let me know.)
i've been puzzling over this too. does anyone know why this wrapping is necessary? (i think this bit is not explained in clojure pills 17 either.)

seancorfield21:12:12

@sogaiu Because each expression (at the top-level) is compiled to a class -- because that's the unit of compilation on the JVM -- as if it were an anonymous function definition and then that (compiled) function-as-class is invoked. (my understanding)

seancorfield21:12:41

(each function is compiled to a class with static invoke methods)

sogaiu21:12:07

thanks for the response -- will need to study more to understand your answer 🙂

andy.fingerhut22:12:29

There are probably under 10 people in the world who know the answer to that question off the top of their head, and unfortunately I am not one of them 🙂 This channel and #clojure-dev are the most reasonable places to ask, so you are in the right place -- it all depends on whether one of those few people happen to be reading.

andy.fingerhut22:12:40

"necessary" might be too strong a word in your question "why this wrapping is necessary", i.e. likely the code could have been implemented differently. It may be that it makes the compiler more straightforward to reduce the number of kinds of 'top level' forms.

andy.fingerhut22:12:49

Also, feel free to delete the code that does that wrapping, compile your custom version of Clojure locally with a different version number, and try it out on a Clojure project of yours and see what happens 🙂 Sometimes that is a quicker way to find an answer.

sogaiu22:12:24

thanks a lot for the feedback and tips -- i guess i should become more familiar with building a custom clojure version 🙂 may be an early version would be easier to get working -- one that doesn't involve spec.

andy.fingerhut22:12:00

Happy to walk you through the steps if you are interested. It is pretty quick and easy once you know how.

sogaiu22:12:36

i'll give it an attempt or three 🙂

andy.fingerhut22:12:15

You should already have Java installed. Install Maven, then from the root of a Clojure source tree, type mvn clean install , and if it succeeds, then near the end of the output it should have a line like the one in my next message. Use the version number there in your org.clojure/clojure dependency version number instead of "1.10.1", e.g. replace it with "1.11.0-master-SNAPSHOT", and run your Clojure code again. It will look in your $HOME/.m2 directory for that locally installed version, as it does for any other version of Clojure that is first downloaded from the Internet and then put into your $HOME/.m2 directory.

andy.fingerhut22:12:23

[INFO] Installing /Users/andy/clj/clojure/target/clojure-1.11.0-master-SNAPSHOT-sources.jar to /Users/andy/.m2/repository/org/clojure/clojure/1.11.0-master-SNAPSHOT/clojure-1.11.0-master-SNAPSHOT-sources.jar

andy.fingerhut22:12:51

If you do not want to run Clojure's built-in tests for some reason (e.g. you made only a tiny change and expect them to pass), you can skip those by instead using mvn -Dmaven.test.skip=true clean install

andy.fingerhut22:12:34

Just think of all the places in the Clojure compiler Java code you could stick in a little System.out.println(...) call and learn all kinds of things 🙂

sogaiu22:12:51

it seems to be working (including my first System.out.println 🙂 ). i was under the impression that there was some kind of extra work involved because of some kind of circular dependency(?) with spec. perhaps that is just a misunderstanding on my part? in any case, thanks for the fishing pole 🎣

jumar08:12:41

It's even more interesting to set a breakpoint in the compiler and step through the process

sogaiu13:12:16

yes, i've been doing that on and off using cursive, but i have found it to be unstable on occasion -- it's fantastic when it works though! i've found it's harder / cumbersome to make significant behavioral changes using a debugger though