clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
emccue 2021-03-23T02:33:31.329500Z

Maybe a real quick question

emccue 2021-03-23T02:33:39.329800Z

lein ring isn't calling my configurator

emccue 2021-03-23T02:34:28.330400Z

:ring {:handler       some.ns/handler
         :init          some.ns/init
         :adapter       {:configurator  some.ns/configurator}
         :open-browser? false
         :stacktrace?   false
         :auto-reload?  false
         :port          3000

emccue 2021-03-23T02:34:52.330800Z

it is definitely using jetty

emccue 2021-03-23T02:35:35.331Z

ring 1.8

emccue 2021-03-23T02:43:24.331400Z

I've also tried the :configurator key flat

seancorfield 2021-03-23T04:58:27.333400Z

@emccue Given that :adapter is pure data and is passed directly to the run-jetty function, I don't see how you can pass a configurator function -- there's no way to resolve a symbol to code.

seancorfield 2021-03-23T05:00:16.335100Z

I think what happens here is that you end up passing the symbol some.ns/configurator into the adapter and that ends up being "called" on the server object -- and ('sym :x) is going to work as a lookup and give you nil.

emccue 2021-03-23T05:08:00.335700Z

thats a mild headache

emccue 2021-03-23T05:08:18.336100Z

since ~some.ns/configurator also doesn't want to work

seancorfield 2021-03-23T05:08:37.336600Z

Because you can't pass a function into Lein's evaluation.

seancorfield 2021-03-23T05:09:59.337800Z

You can only use ~ to evaluate things that can be serialized: strings, numbers, data structures.

seancorfield 2021-03-23T05:10:31.338300Z

My advice: don't use lein-ring. Start the server yourself and then you have full control over it.

seancorfield 2021-03-23T05:17:05.339200Z

Even back when I was still using Leiningen (years ago now), I never used lein-ring for dealing with servers: it just wasn't worth the additional complexity in my view.

βž• 3
danielneal 2021-03-23T11:09:11.340800Z

I'm trying to benchmark a slow function using criterium, but I want to reduce the sample count a bit or it'll take hours. I've tried

(binding [crit/*sample-count* 10]
     (crit/bench
       ...expr..))
and
(crit/bench
    ...expr..
    :samples 10)
but neither seem to work, what am I missing?

ordnungswidrig 2021-03-23T11:50:50.341200Z

Anybody familar with dtype-next / tech.v3.datatype.functional?

Jean 2021-03-23T12:29:49.343400Z

Hi! I work on an old project with clj-time I don’t understand why this (t/to-time-zone (t/now) (t/time-zone-for-id "America/New_York")) return the UTC date-time and not the right date timezoned. Someone has already had the problem?

phoenixjj 2021-03-23T12:45:00.343500Z

which version clj-time you are using ?

Jean 2021-03-23T12:52:11.343700Z

[clj-time "0.15.2"]

restenb 2021-03-23T13:24:09.344300Z

is there a way to put a transducer on a returned channel?

restenb 2021-03-23T13:25:06.345400Z

particularly I'd like to combine core.async/timeout with a transducer

nilern 2021-03-23T13:29:20.345800Z

pipe?

phoenixjj 2021-03-23T13:32:18.346800Z

If you run above code in repl, what is the output ?

nilern 2021-03-23T13:33:40.347500Z

It is a bit verbose but I don't see a fn that would create the "derived" channel for you

phoenixjj 2021-03-23T13:34:10.347600Z

=> (t/to-time-zone (t/now) (t/time-zone-for-id "America/New_York")) #object[org.joda.time.DateTime 0x7d6955a "2021-03-23T09:31:20.371-04:00"]

Jean 2021-03-23T13:35:29.347800Z

I got this #clj-time/date-time "2021-03-23T13:35:12.899Z"

phoenixjj 2021-03-23T13:37:40.348Z

I am also using [clj-time "0.15.2"]

phoenixjj 2021-03-23T13:38:14.348200Z

(require '[clj-time.core :as t])

phoenixjj 2021-03-23T13:38:44.348400Z

=> (t/to-time-zone (t/now) (t/time-zone-for-id "America/New_York")) #object[org.joda.time.DateTime 0x4238423f "2021-03-23T09:38:17.871-04:00"]

Jean 2021-03-23T13:41:55.348600Z

Jean 2021-03-23T13:42:27.348800Z

:thinking_face:

phoenixjj 2021-03-23T13:43:24.349Z

What is output of this ?

phoenixjj 2021-03-23T13:43:30.349200Z

user> (java.time.ZonedDateTime/ofInstant (java.time.Instant/now) (java.time.ZoneId/of "America/New_York")) #object[java.time.ZonedDateTime 0xba90dd6 "2021-03-23T09:42:55.125283-04:00[America/New_York]"]

Jean 2021-03-23T13:44:31.349400Z

Good output #object[java.time.ZonedDateTime 0x22e1075 "2021-03-23T09:44:00.907-04:00[America/New_York]"]

phoenixjj 2021-03-23T13:50:07.349600Z

(require '[clj-time.local :as l])
(l/local-now)
Are you getting correct local time ?

Jean 2021-03-23T13:52:51.349800Z

I got the UTC date

chrisn 2021-03-23T13:53:45.350Z

I can help you πŸ™‚. What is up?

vemv 2021-03-23T14:44:55.352500Z

I read @dpsutton’s https://dev.to/dpsutton/exploring-the-core-cache-api-57al article again and was somewhat scared to use core.cache (never have, but I remember a peer using it in a past job... again it was tricky) Wondering if it would make sense to implement clojure.lang.IAtom backed by core.cache? That way one would use clojure.core/swap! and have the nuances abstracted away. Anyone has tried that?

dharrigan 2021-03-23T14:59:29.353Z

I believe there was some discussion around this (@seancorfield) and the recommendation is to use the wrappers

πŸ‘ 1
dpsutton 2021-03-23T15:01:23.353600Z

i consider the cache protocol to be private and people should only ever use wrapped/through or wrapped/through-cache

πŸ‘ 2
πŸ™‚ 1
vemv 2021-03-24T22:31:39.414800Z

Is there as strong difference between wrapped/lookup-or-miss and wrapped/through-cache? (I observed that the former uses the non-wrapped through-cache so it might be a 'superset' of the functionality?) I tried to understand the difference but sadly in the repo wrapped/through-cache has no unit tests and a worse docstring than wrapped/lookup-or-miss so I'm confused about what the wrapped/through-cache fn actually does

dpsutton 2021-03-24T22:38:21.415100Z

ah good point. i think that's the one that can prevent needless spinning under contention

dpsutton 2021-03-24T22:38:38.415300Z

i'd do some experiements. spin up 30 threads hitting your cache and count the number of times something is computed

dpsutton 2021-03-24T22:38:45.415500Z

i think there was something like that in that article

vemv 2021-03-24T22:40:18.415700Z

Yeah I got that impression from the article and source I expect contention to be low/irrelevant so probably I'll sleep calmer with max 10 attempts

vemv 2021-03-24T22:50:26.416Z

Curious, you include clojure.core.cache.wrapped/evict under the 'footgun' category But wanting to immediately overwrite a key with a different new value seems a quite extremely common use case? (`lookup-or-miss`/`through-cache` doesn't appear to help here, not without waiting for the cache entry to naturally expire) Maybe the mistake is mine for thinking of these caches as atoms (as opposed to things that can have disparate implementations)?

dpsutton 2021-03-24T22:51:36.416200Z

i think you really shouldn't call evict yourself. the cache has strategies to call evict. but i suppose if you wanted to override you could

vemv 2021-03-24T22:55:47.416400Z

yes I suppose that eviction is essential to all these caches, they have to perform eviction sooner or later :) but I suspect depending on the use case, waiting an indeterminate amount of time (or having dropped writes) is not what one wants. OTOH, I suppose that if one used evict recklessly one could increase contention or get nil reads

vemv 2021-03-24T22:56:08.416600Z

(btw I'm just testing out my own knowledge, and not really questioning anything)

dharrigan 2021-03-23T15:05:00.354300Z

Wasn't there a discussion in clojure q&a or clojureverse? or was I dreaming πŸ™‚

dharrigan 2021-03-23T15:05:05.354500Z

maybe it was here

vncz 2021-03-23T15:37:32.355300Z

Is there a way to rewrite this and avoid an anonymous function? (filter #(= (:type %) "sha1"))

dpsutton 2021-03-23T15:38:37.355700Z

(filter (comp #{"sha1"} :type))

dpsutton 2021-03-23T15:39:40.356600Z

common idiom. up to you if you think its more clear. once you see it a bunch it is but whether it is "better" is pretty 50:50 to me

nilern 2021-03-23T15:40:07.357100Z

It is no shorter, but slower πŸ˜…

vemv 2021-03-23T15:43:03.358800Z

Depends. #{"sha1"} is compiled just once as a constant and barely has a noticeable difference vs. = #{x} creates a set in runtime. Set creation is somewhat slow

piotrts 2021-03-23T15:44:21.360700Z

I think there is nothing wrong with (filter #(= (:type %) "sha1")) , the intent is clear and much easier to read than (filter (comp #{"sha1"} :type)) (at least for me)

☝️ 1
p-himik 2021-03-23T15:44:27.360900Z

Why would you want to avoid having an anonymous function there in the first place? If you just mean having #(...) (after all, comp also creates an anonymous function), then you can simply use the more verbose (fn [x] ...) syntax.

p-himik 2021-03-23T15:44:46.361400Z

FWIW, personally I would write it as #(-> % :type (= "sha1")). Or as the initial variant - doesn't really matter.

nilern 2021-03-23T15:46:07.362400Z

#( is ugly but pointfree is harder to understand

nilern 2021-03-23T15:46:58.363200Z

I have seen a (fn-> :type (= "sha1")) macro in some projects

πŸ‘€ 1
vemv 2021-03-23T15:48:54.364900Z

pretty futile to try finding an objective truth for these :) https://lambdaisland.com/blog/2019-12-06-advent-of-parens-6-a-small-idiom can used further evidence that some (reputed) people like the idiom performance is objective though, so when in doubt I wouldn't use #{x} as a predicate

Derek Passen 2021-03-23T15:51:23.366500Z

If the key didn’t shadow a built-in, I find (filter (fn [{:keys [type]}] (= type "sha1"))) most readable

emccue 2021-03-23T15:52:51.368200Z

@vincenz.chianese

(defn sha1? [hashing-procedure]
  (= (:type hashing-procedure) "sha1"))

...
(filter sha1?)

emccue 2021-03-23T15:53:30.369400Z

or

vncz 2021-03-23T15:53:34.369900Z

Yeah…I do not know, I do not feel it deserves to be a function that can be reused

nilern 2021-03-23T15:53:39.370400Z

There are only a few characters to save unless you go for a separate function

vncz 2021-03-23T15:53:52.371300Z

t=>t.type === 'sha1" that's really it, not worth spending more time on it I gues

emccue 2021-03-23T15:54:03.371700Z

(let [sha1? (fn [hashing-procedure]
              (= (:type hashing-procedure) "sha1"))]
  (filter sha1?))

emccue 2021-03-23T15:54:16.372100Z

giving it a name and giving it a place in a namespace are seperate

emccue 2021-03-23T15:54:42.372800Z

just pointing out that naming the function and typing the extra characters has some benefit

emccue 2021-03-23T15:54:59.373100Z

hence why python is structured to only allow that way

p-himik 2021-03-23T15:57:10.373200Z

What do you mean? It does have lambda.

p-himik 2021-03-23T15:57:28.373400Z

It's just that it's impossible to not return something from it.

nilern 2021-03-23T15:57:59.373700Z

Or have more than one expression

p-himik 2021-03-23T15:58:32.373900Z

Ah, right. Tuples to the rescue. :)

nilern 2021-03-23T15:58:55.374100Z

Can't do statements even with tuples

nilern 2021-03-23T15:59:47.374300Z

They say it's because of parsing issues but somehow Haskell has multiline lambdas

p-himik 2021-03-23T16:01:35.374500Z

But with lambdas you don't needs statements - anything it still computable. :) Albeit absolutely impractical.

nilern 2021-03-23T16:05:26.374900Z

And they have been adding expression variants of statements little by little (`[x + 1 for x in xs]`, foo if bar else baz, foo := bar) πŸ˜‚

p-himik 2021-03-23T16:07:09.375100Z

I'm so happy that I have stopped almost all involvement with Python right before they introduced the walrus operator.

nilern 2021-03-23T16:09:32.375300Z

What? Pascal forever!

p-himik 2021-03-23T16:11:33.375500Z

Kernighan disagrees. :P

nilern 2021-03-23T16:12:44.375700Z

Such a controversial operator https://mail.python.org/pipermail/python-committers/2018-July/005664.html

nilern 2021-03-23T16:12:57.375900Z

> Now that PEP 572 is done, I don't ever want to have to fight so hard for a > PEP and find that so many people despise my decisions.

Brendan Foote 2021-03-23T16:36:25.376700Z

does anyone have any experience with Tomcat not being able to run a Luminus uberwar with an error of ClassNotFoundException for ServletContextlistener? I found a SO post with the same error, but none of the responses seem to have helped.

vemv 2021-03-23T16:43:23.376800Z

I'd start by inspecting the uberwar and verifying whether that class exists there

Brendan Foote 2021-03-23T16:56:12.377200Z

there is a file called servlet-api.jar in tomcat's /lib folder, but there isn't anything with that name inside the war. Would that mean uberwar isn't including it? I tried creating a new project with "lein new luminus ... +uberwar +servlet", but I got the same error

emccue 2021-03-23T16:56:12.377400Z

Python doesn't improve the lambda specifically because of a deliberate design choice to make people name their functions

emccue 2021-03-23T16:57:12.377600Z

hence the helpers in operator and whatnot

vemv 2021-03-23T16:57:53.377800Z

I don't have much expertise in these area, sorry. I just hinted that uberwars should be inspectable If a stock lein new luminus ... +uberwar +servlet app doesn't work out of the box, that would seem a good thing to report as a github issue

Brendan Foote 2021-03-23T19:57:55.379300Z

Okay, I just logged the issue with lein-uberwar

borkdude 2021-03-23T21:05:09.380900Z

(maybe use https://clojure.org in the topic?)

lilactown 2021-03-23T23:21:10.382100Z

is there an example anyone has off hand of what the defn params list as attr-map? is used for?

2021-03-23T23:23:19.382400Z

ins)user=> (defn foo "a function" {:has-arbitrary-meta true} [])
#'user/foo
(ins)user=> (meta #'foo)
{:arglists ([]), :doc "a function", :has-arbitrary-meta true, :line 1, :column 1, :file "NO_SOURCE_PATH", :name foo, :ns #object[clojure.lang.Namespace 0x72458efc "user"]}

2021-03-23T23:23:23.382700Z

it gets merged to metadata

lilactown 2021-03-23T23:23:30.382900Z

I see

2021-03-23T23:24:02.383300Z

it's one of the N ways to attach metadata to a function's var

dpsutton 2021-03-23T23:25:42.384200Z

the docstring mentions this as well: > Same as (def name (fn [params* ] exprs*)) or (def > name (fn ([params* ] exprs*)+)) with any doc-string or attrs added > to the var metadata. also the spec calls it meta in the spec definition: :meta (? map?). But i agree it is a bit hard to parse that that's what's happening.

2021-03-23T23:26:43.384600Z

only tenuously related, I'm reminded of this trick

(ins)user=> (defn bar {:macro true} [_ _ form] (reverse form))
#'user/bar
(ins)user=> (bar (1 1 +))
2

😱 2
2021-03-23T23:26:51.384800Z

macros without defmacro

dpsutton 2021-03-23T23:28:57.385500Z

i guess .setMacro sets that metadata and extends the signature for &form and &env?

2021-03-23T23:29:47.385900Z

that sounds like what it would need to do

2021-03-23T23:34:02.386Z

which got me thinking about making point-free macros, or something approaching it at least

(cmd)user=> (defn as-macro [f] (fn [& args] (apply f (drop 2 args))))
#'user/as-macro
(cmd)user=> (def baz (as-macro reverse))
#'user/baz
(cmd)user=> (alter-meta! #'baz assoc :macro true)
{:line 1, :column 1, :file "NO_SOURCE_PATH", :name baz, :ns #object[clojure.lang.Namespace 0x72458efc "user"], :macro true}
(cmd)user=> (baz (1 1 +))
2

2021-03-23T23:35:29.386800Z

it only does the metadata part, something else must add the invisible args

2021-03-23T23:36:39.387200Z

oh, there's a binding in defmacro's body called "add-implicit-args"

dpsutton 2021-03-23T23:42:29.387600Z

That makes a lot of sense