Fork me on GitHub
#clojure
<
2022-02-23
>
rmxm00:02:55

Running into problem running lein repl inside container. On OSX works as expected, but on WSL2 somehow getting clj-container exited with code 0 . I have project.clj, where I run one function (launching mount). Expected behaviour that happens on mac is that repl opens port, runs the code defined in project.clj and keeps on waiting. Exit is happening on WSL2 - no idea why it exits. When I run solo container with term attached (outside compose) it run fine.

rmxm00:02:04

Ok, if anybody runs into the same show. Running lein repl :headless solves the deal. I am betting its something regarding said terminal attachment. Thanks for reading my story 🙂

lilactown06:02:40

(list? (a b c)) ;; => false`

seancorfield06:02:07

dev=> (type `(a b c))
clojure.lang.Cons
So it's not a list.

seancorfield06:02:24

list? is a really weird predicate that pretty much no one uses.

seancorfield06:02:01

dev=> (list? (map identity '[a b c]))
false

seancorfield06:02:14

(because a LazySeq is not a list either)

lilactown06:02:33

what's the right thing to do here? seq?

seancorfield06:02:49

What question are you trying to ask?

seancorfield06:02:52

dev=> (list? (range 3))
false

seancorfield06:02:13

sequential? perhaps? seqable? maybe?

lilactown06:02:29

I have a definition like this

(def system
  `(app
    (db {:uri (config :db/uri)})
    (dir-watcher-pool (config :dirs))))

lilactown06:02:11

l'd like to walk it and handle all structures of the form (<sym> <args>)

lilactown06:02:43

I naively thought (and (list? x) (symbol? (first x))) would suffice

seancorfield06:02:01

dev=> (doseq [l [() '(a b c) `(a b c) (map identity '[a b c]) (range 3)]
 #_=>         p [list? seq? seqable? sequential?]]
 #_=>   (println (type p) l (p l)))
clojure.core$list_QMARK_ () true
clojure.core$seq_QMARK___5471 () true
clojure.core$seqable_QMARK_ () true
clojure.core$sequential_QMARK_ () true
clojure.core$list_QMARK_ (a b c) true
clojure.core$seq_QMARK___5471 (a b c) true
clojure.core$seqable_QMARK_ (a b c) true
clojure.core$sequential_QMARK_ (a b c) true
clojure.core$list_QMARK_ (dev/a dev/b dev/c) false
clojure.core$seq_QMARK___5471 (dev/a dev/b dev/c) true
clojure.core$seqable_QMARK_ (dev/a dev/b dev/c) true
clojure.core$sequential_QMARK_ (dev/a dev/b dev/c) true
clojure.core$list_QMARK_ (a b c) false
clojure.core$seq_QMARK___5471 (a b c) true
clojure.core$seqable_QMARK_ (a b c) true
clojure.core$sequential_QMARK_ (a b c) true
clojure.core$list_QMARK_ (0 1 2) false
clojure.core$seq_QMARK___5471 (0 1 2) true
clojure.core$seqable_QMARK_ (0 1 2) true
clojure.core$sequential_QMARK_ (0 1 2) true

lilactown06:02:46

essentially I want something that is either a list or a cons

seancorfield06:02:06

But not a vector? sequential? will be true on a vector.

lilactown06:02:12

that's right

lilactown06:02:05

guess I'll check the type

seancorfield06:02:51

Several of those predicates test instance? so you need to know what the underlying type hierarchy is.

lilactown06:02:54

oh and postwalk converts it to a lazyseq

lilactown06:02:11

so I guess I was doomed from the start

seancorfield06:02:48

In HoneySQL I just used sequential? and allowed lists or vectors... maybe seq? will be enough for your use case? (it's false on vectors)

seancorfield06:02:14

(but I think there are cases where you get something list-like that is not seq? but I can't remember)

hiredman06:02:22

Clojure persistentlists are also seqs

hiredman06:02:38

By which I mean seq? should have you covered

lilactown06:02:28

yeah I'll go with that

quoll17:02:56

I realize that I’m late, but just to add to it… Clojure will eval things that return true for a seq?, so this looks to align with what you want

jeff tang08:02:48

How come Clojure keywords only support up to one level of namespaces? Like why can’t I do :clojure/community/slack and :clojure/community/zulip

tatut08:02:20

usually one would use java style "package" names separated by dots

tatut08:02:33

like :some.deep.ns/a-key

mkvlr08:02:15

I think you can make them using keyword but can’t read them (keyword "what/is/happening?");; => :what/is/happening?

jeff tang08:02:55

Indeed, that is how Clojure package namespaces work as well e.g.: app.views.button Why not always use the period as the delimiter then if slashes can only be used once?

tatut08:02:27

you can destructure keys in an ns {:foo.bar/keys [a-key other-key]}

tatut08:02:48

and it mirrors how vars work, some.deep.ns/some-var

tatut08:02:59

you can access the namespace and name parts separately, but I guess nothing prevents you from having raw keywords with just dotted names

👍 1
p-himik11:02:17

> Why not always use the period as the delimiter then if slashes can only be used once? If this were true, would a.b.c be a namespace in file a/b/c.clj or a var c in namespace a.b? With slashes delimiting namespaces from their contents it's clear for both the user and the machine.

jeff tang11:02:51

it's ironic that that there are two concepts of namespaces, colliding in their name and usage

p-himik11:02:13

Not sure what you mean.

tatut13:02:48

the dots in namespaces do have a mapping to file paths, but I otherwise I don't think they have any semantic

tatut13:02:22

you could do use :foo-bar-baz/a-key just as easily

tatut13:02:22

I don't see that there are 2 namespaces... it's just that namespace names have some meaning

eccentric J12:02:20

This could be me just being rusty with clojure but I should be able to create src/promesa/core.cljs and create new macros that are accessible through p/new-macro given (require '[promesa.core :as p]) right?

p-himik12:02:29

Was the path really meant to be cljs and not clj ?

eccentric J12:02:58

Working in cljs but figured it would be the same regardless of host?

p-himik12:02:54

It's not the same, alas. In Clojure, you can add macros anywhere - you can even use them in the same file and ns where you define them. In CLJS, that's not the case. If it's not a self-hosted environment, you have to have all your macros in either a .clj file or in a .cljc file (don't do the latter - it's easy to make a hard-to-fix mess). If it's a self-hosted environment, you have to have a .cljs file with your macros but the corresponding ns has to be required with :require-macros.

eccentric J13:02:33

I'm using nbb so macros are supported the clojure way https://replit.com/@eccentric-j/nbb-with-redefs-async#src/cli/core.cljs just trying to understand how to extend the funcool.promesa/core ns

p-himik13:02:09

I would ask in #nbb then. :) No clue what peculiarities that platform might have. But in CLJ, your approach would work. But note that adding a/b.clj to your sources while some jar on your classpath already has a/b.clj will not extend that a.b namespace but simply replace it (assuming src appears on the classpath earlier than that jar).

eccentric J14:02:15

Wanted to know what the intended behavior was with clojure so that I can understand if nbb is consistent or not. Plus I've been terrorizing that channel with questions lately. Sounds like that approach would not work

p-himik14:02:35

Why would you want to add a macro to some existing third-party namespace instead of just using one of your own namespaces, like promesa-utils or whatever?

eccentric J14:02:41

Developing a macro for an upstream PR https://github.com/funcool/promesa/pull/102 but wanted to extend the existing namespace so the naming would be correct and I can update the library, remove my draft version, and everything would still work in my project. I settled for just adding it to my utils.cljs but was curious if there was a better way as it's used across a few files

p-himik14:02:10

A better way would be to develop all changes in a custom fork and depend on that fork in your project. And when the upstream lib incorporates your changes, you can just swap the dependency.

hanDerPeder12:02:59

This doesn’t work (let did not conform to spec)

(let []
  :clojure.spec.alpha/invalid)
workaround
(let []
  (when true
   :clojure.spec.alpha/invalid))
Bug? on 1.10.3

mpenet12:02:49

isn't this a case of a conformed value being equal to c.s.a/invalid when the let is validated causing it to fail

mpenet12:02:15

iirc you can do (def invalid :clojure.spec.alpha/invalid) and then refer to invalid in your code

mpenet12:02:20

should work

mpenet12:02:14

it only happens with specced macros iirc

hanDerPeder12:02:29

writing a conformer, which is supposed to return :clojure.spec.alpha/invalid on failure.

hanDerPeder12:02:30

I’ll go with your way @mpenet and add an explanation to the var, thanks!

orestis14:02:30

A misconfiguration from a client resulted in us getting a load test for free 🙂 From a usual load of max 3req/s, we went to 10req/s. Our CPU usage went to roughly 90-95%. Obviously we adjusted our autoscaling policies, but I'm curious to know what exactly was consuming that much CPU time. Is it possible to generate something like a flamegraph but in production? I'm curious on whether it was logging, printing stacktraces, JSON formatting or something completely different that was spinning...

javahippie14:02:55

For something like this we had the FlightRecorder running constantly on Prod. I’m not sure if is possible to analyze the event retrospectively, though Edit: Also might cause a 1-2% performance hit for the app while it’s running

orestis14:02:16

Retrospectively probably not, I wouldn't expect that. Just to be prepared if it happens again, and to establish a baseline.

orestis14:02:23

Oh that's nice. So essentially you would e.g. keep dumping JFR files every, say, hour? Then if you wanted to look into an incident, you would get the JFR file of that hour and see what was the CPU/memory activity plus the stack samples? That's really helpful.

javahippie14:02:02

That should be possible via triggers, yes. And afterwards you could read the dump with Misson Control or VisualVM.

orestis15:02:38

CodeGuru seems to do something similar https://aws.amazon.com/blogs/machine-learning/optimizing-application-performance-with-amazon-codeguru-profiler/ but I can't find if they use JFR behind the scenes or not.

javahippie15:02:27

Seems to not have any compile time dependencies at all, so it’s probably their own https://mvnrepository.com/artifact/software.amazon.awssdk/codeguruprofiler/2.17.134

javahippie15:02:18

If Codeguru aggregates it in a single place, it sounds like the nicer solution for AWS 👍

orestis16:02:18

They might be using https://github.com/jvm-profiling-tools/async-profiler which is what the Clojure-goes-fast profiler uses.

Ben Sless19:02:40

You can generate a flame graph in production by embedding clj-async-profiler in your application. Pretty easy

Ben Sless19:02:05

Though you can also run this profiling on you local machine

Ben Sless19:02:45

Moreover, if you collect JVM metrics besides host metrics, check your heap and GC graphs

Ben Sless19:02:03

How did you start and run your application?

pinkfrog14:02:48

Hi. How to achieve the same purpose of a function scoped static initializer in cpp, like this:

void func() {
    // this foo is only initialized once, at the first time when func() is called
    static foo = some_other_func();
    // do some work
}
I’d like to have some part of logic to be executed only once. Defonce is not relevant here as it pollutes the namespace.

kraf14:02:43

Just so I understand correctly, multiple calls to func do not call some_other_func after the first invocation?

kraf14:02:13

Why doesn't a closure work?

kraf14:02:30

Ah I get it 😅

Zohar Kelrich15:02:17

Is this about right?

(let [foo (delay (some-other-func))]
  (defn func []
     (work-with @foo)))

pinkfrog15:02:29

Probably I shall stop clj-kondo complaining about the defn inside let.

kraf15:02:30

(def func
  (let [foo (delay (some-other-func))]
    (fn [] ...)))

👍 1
Alex Miller (Clojure team)14:02:14

it has the downside of requiring the result to be deref'ed but has the single execution semantics

Zohar Kelrich15:02:47

I think I found a Clojure bug.

(let [v ##NaN] (= v v))
=> false
(let [f #(= % %)]
  (f ##NaN))
=> true
That second one should be false as well, but it's not, because of boxing

😓 1
andy.fingerhut15:02:46

Why do you say it should be false?

andy.fingerhut15:02:05

It is true because the values are identical?, as someone explained later. I agree this is surprising, but Clojure's = for efficiency relies on quickly returning true when its two args are identical? (i.e. same object in memory). Making a special case in = to check that they are ##NaN would slow down = for all values.

andy.fingerhut15:02:12

I agree it is confusing, but not sure I would call it a bug.

Zohar Kelrich15:02:19

Because ##NaN is defined to not equal ##NaN

Zohar Kelrich15:02:31

This means that an "optimization" is incorrect

andy.fingerhut16:02:00

Use == to compare numbers numerically

andy.fingerhut16:02:44

user=> (let [v ##NaN] (== v v))
false
user=> (let [f #(== % %)] (f ##NaN))
false

Zohar Kelrich16:02:51

This isn't about ==. This is = being too sensitive, and breaking value equality

andy.fingerhut16:02:23

You can ask. I wouldn't be surprised if the answer from Clojure maintainers is as above, but I am not a Clojure maintainer, so I will let them choose their own answer.

andy.fingerhut16:02:51

I am only giving you my best educated guess as to the reason. Efficiency is a huge concern for them.

andy.fingerhut16:02:46

You might want to file a bug against Java, too, while you're at it:

(.equals ##NaN ##NaN)
true

andy.fingerhut16:02:02

although that behavior is documented, I believe.

andy.fingerhut16:02:20

Java numeric comparisons return false for NaN, I believe.

andy.fingerhut16:02:18

I've filed dozens of bugs in the Clojure core implementation myself over the last 10 years, so I'm not claiming it is all perfect and laid out like holy texts, or anything. Just that sometimes the answer isn't what you want it to be.

dpsutton15:02:10

That’s interesting

Joshua Suskalo15:02:36

so reference equality short-circuiting is causing the value equality of nan to not be checked? that's interesting

dpsutton15:02:00

@zohark i’d make a question on http://ask.clojure.org with this question. Quite possible its a known issue. But if not, that’s the best place to get thoughtful eyes on it if a fix is warranted

jmckitrick17:02:35

Style question: is there a compelling reason (not) to use letfn vs fn in a let binding? Other than needing to call other functions declared the same way in that set of bindings?

Alex Miller (Clojure team)17:02:34

letfn is a little special in letting you define a function that you can use in a self call (or multiple fns you can call from each other)

Alex Miller (Clojure team)17:02:14

99% of the time you don't need that power and it probably doesn't matter

jmckitrick17:02:51

ok, that’s what I figured… if I don’t need to recurse or call another fn at that level…

1
hiredman18:02:40

a lot of people hate letfn because it has forms like (x ....) where x is not a special form, function call, or macro

hiredman18:02:56

I prefer it over let binding functions though, and have no supporting reasoning

2
metal 2
hiredman18:02:02

Elements of Clojure has a section on letfn which basically makes the case against using it unless absolutely needed

jmckitrick18:02:47

There are a lot of features of common lisp that are almost completely unneeded in clojure. This seems like one of them.

hiredman18:02:55

I mean, why have it at all, everyone could just write their own https://gist.github.com/hiredman/1179073

quoll21:02:43

Self recursion can always happen in a let using the optional name? that not everyone seems to be aware of, but the mutual references between functions feature is very cool! 🙂

jmckitrick02:02:33

@U051N6TTC not sure I know what you mean about name? . Could you explain? 😁

quoll02:02:32

Sure…

(def fib (fn f [n] (if (< n 2) 1 (+ (f (dec n)) (f (- n 2))))))

quoll02:02:17

The use of “f” here is an optional name? argument that can be provided to fn. It allows anonymous functions to refer to themselves.

quoll02:02:06

It shows up in the documentation for fn:

=> (doc fn)
-------------------------
clojure.core/fn
  (fn name? [params*] exprs*)
  (fn name? ([params*] exprs*) +)
([& sigs])
Special Form
  params => positional-params* , or positional-params* & next-param
  positional-param => binding-form
  next-param => binding-form
  name => symbol

  Defines a function

  Please see 
Spec
  args: (cat :fn-name (? simple-symbol?) :fn-tail (alt :arity-1 :clojure.core.specs.alpha/params+body :arity-n (+ (spec :clojure.core.specs.alpha/params+body))))
  ret: any?

jmckitrick02:02:52

Ohhh. I was looking under let lol

jmckitrick02:02:25

I think I have seen that feature, but not used it. Yet.

Stel Abrego20:02:45

Hey friends, I have a question about namespaces. I've noticed that many popular Clojure libraries don't use the reverse domain name namespace convention recommended by the Clojure https://guide.clojure.style/#namespace-declaration. I'm writing a library right now and I'm torn between the easier to remember foobarbaz.api or the fully qualified codes.stel.foobarbaz.api . Is it ok to drop the reverse domain name if the libary has a fairly unique name? Also, I would like to group all of the public API into a single namespace. From what I can tell, common names for such a namespace are api, interface, and core. I'm leaning towards api, like Datomic. Any reason I shouldn't?

lukasz20:02:26

Is that a packaging concern or the API? Because you can ship your package under fully qualified name, but your namespaces do not have to use that format

lukasz20:02:13

So your maven coordinates can be codes.stel/foobarbaz but your namespaces only use foobarbaz

dpsutton20:02:24

it is nice to having something that’s a bit identifiable to you so that namespaces don’t collide when required

dpsutton20:02:14

for me i’d use dpsutton.foobarbaz just incase someone else has a really helpful foobarbaz library and then also think they should take that top level

Stel Abrego20:02:18

@U0JEFEZH6 That's a good point. I'm planning on using codes.stel/foobarbaz as the maven coordinates. I was mostly wondering about the namespace collision issue.

dpsutton20:02:34

for instance stuart sierra’s component library has coordinates

com.stuartsierra/component {:mvn/version "1.0.0"}
and namespace
com.stuartsierra.component
Personally i would have just used stuartsierra.component for the ns. But you can see the danger had he just named his namespace component. Single segment namespaces are heavily discouraged for this reason

Stel Abrego20:02:52

@U11BV7MTK Ah yes that makes sense, I feel like even component.core would be a collision risk. I'm leaning towards using fully-qualified namespaces.

potetm20:02:00

reverse domain guarantees uniqueness if you own the domain

potetm20:02:01

is the diff

potetm20:02:12

as opposed to, “probably fine”

dpsutton20:02:49

Nothing prevents me from putting namespaces with others reverse dns though, right?

truestory 1
😿 1
seancorfield20:02:52

@U019RSW97UZ "I'm planning on using codes.stel/foobarbaz as the maven coordinates." -- I assume you own a https://stel.codes domain and can verify that for the Clojars team? See https://github.com/clojars/clojars-web/wiki/Verified-Group-Names

Stel Abrego21:02:01

@U04V70XH6 Hey Sean, yes https://stel.codes is my domain. I was not aware of the Clojars verification. I will look into that. Thank you!

Joshua Suskalo21:02:55

clojars verification obviously also does not mess with your namespace names.

Joshua Suskalo21:02:21

Personally I go the route of making a unique name, googling the name with clojure, and then publishing with project.core for single-ns projects, and project.module for every module in a multi-ns project. This works out fine in a lot of communities, I haven't seen issues in practice with it in the clojure community. The main time you see different toplevel nses with the same name is in forks, and it would be rare that you would want to forks of the same project in your project dependencies at once.

flowthing21:02:14

I'm toying with the idea of making a REPL that supports picking up the current ns for both read and eval from an atom so that I can set the ns out of band. Is this a dumb approach? https://gist.github.com/eerohele/45a255b249a2154431bfd70502cb625a

flowthing21:02:39

It certainly seems a bit hacky, but 🤷 .