Fork me on GitHub
#clojure
<
2021-03-23
>
emccue02:03:31

Maybe a real quick question

emccue02:03:39

lein ring isn't calling my configurator

emccue02:03:28

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

emccue02:03:52

it is definitely using jetty

emccue02:03:24

I've also tried the :configurator key flat

seancorfield04:03:27

@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.

seancorfield05:03:16

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.

emccue05:03:00

thats a mild headache

emccue05:03:18

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

seancorfield05:03:37

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

seancorfield05:03:59

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

seancorfield05:03:31

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

seancorfield05:03:05

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.

โž• 9
danielneal11:03:11

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?

ordnungswidrig11:03:50

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

chrisn13:03:45

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

J12:03:49

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?

phoenixjj12:03:00

which version clj-time you are using ?

J12:03:11

[clj-time "0.15.2"]

phoenixjj13:03:18

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

phoenixjj13:03:10

=> (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"]

J13:03:29

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

phoenixjj13:03:40

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

phoenixjj13:03:14

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

phoenixjj13:03:44

=> (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"]

J13:03:27

:thinking_face:

phoenixjj13:03:24

What is output of this ?

phoenixjj13:03:30

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]"]

J13:03:31

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

phoenixjj13:03:07

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

J13:03:51

I got the UTC date

restenb13:03:09

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

restenb13:03:06

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

nilern13:03:40

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

vemv14:03:55

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?

dharrigan14:03:29

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

๐Ÿ‘ 3
dpsutton15:03:23

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

๐Ÿ‘ 6
๐Ÿ™‚ 3
vemv22:03:39

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

dpsutton22:03:21

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

dpsutton22:03:38

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

dpsutton22:03:45

i think there was something like that in that article

vemv22:03:18

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

vemv22:03:26

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)?

dpsutton22:03:36

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

vemv22:03:47

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

vemv22:03:08

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

dharrigan15:03:00

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

dharrigan15:03:05

maybe it was here

vncz15:03:32

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

dpsutton15:03:37

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

dpsutton15:03:40

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

nilern15:03:07

It is no shorter, but slower ๐Ÿ˜…

vemv15:03:03

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

piotrts15:03:21

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)

โ˜๏ธ 3
p-himik15:03:27

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.

vncz15:03:34

I was just trying to see if there was a way to write less code. If there's not, I'll stick with the current solution ๐Ÿ™‚

๐Ÿ™‚ 3
p-himik15:03:46

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

nilern15:03:07

#( is ugly but pointfree is harder to understand

nilern15:03:58

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

๐Ÿ‘€ 3
vemv15:03:54

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

Derek15:03:23

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

emccue15:03:51

@vincenz.chianese

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

...
(filter sha1?)

vncz15:03:34

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

nilern15:03:39

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

vncz15:03:52

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

emccue15:03:03

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

emccue15:03:16

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

emccue15:03:42

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

emccue15:03:59

hence why python is structured to only allow that way

p-himik15:03:10

What do you mean? It does have lambda.

p-himik15:03:28

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

nilern15:03:59

Or have more than one expression

p-himik15:03:32

Ah, right. Tuples to the rescue. :)

nilern15:03:55

Can't do statements even with tuples

nilern15:03:47

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

p-himik16:03:35

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

nilern16:03:26

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-himik16:03:09

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

nilern16:03:32

What? Pascal forever!

p-himik16:03:33

Kernighan disagrees. :P

nilern16:03:57

> 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.

emccue16:03:12

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

emccue16:03:12

hence the helpers in operator and whatnot

Brendan Foote16:03:25

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.

vemv16:03:23

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

Brendan Foote16:03:12

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

vemv16:03:53

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 Foote19:03:55

Okay, I just logged the issue with lein-uberwar

borkdude21:03:09

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

lilactown23:03:10

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

noisesmith23:03:19

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"]}

noisesmith23:03:23

it gets merged to metadata

noisesmith23:03:02

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

dpsutton23:03:42

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.

noisesmith23:03:43

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

๐Ÿ˜ฑ 6
noisesmith23:03:02

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

noisesmith23:03:51

macros without defmacro

dpsutton23:03:57

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

noisesmith23:03:47

that sounds like what it would need to do

noisesmith23:03:29

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

noisesmith23:03:39

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

dpsutton23:03:29

That makes a lot of sense