clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
richiardiandrea 2021-03-18T00:07:01.085700Z

it seems like the instrumentation check my fully qualified key even if not in s/keys

alexmiller 2021-03-18T00:21:52.086Z

It does

alexmiller 2021-03-18T00:22:10.086400Z

The doc string covers this

šŸ‘ 1
NoahTheDuke 2021-03-18T16:59:41.089700Z

(defn destr [& {:keys [a b] :as opts}]
  [a b opts])

(destr :a 1)
->[1 nil {:a 1}]

(destr {:a 1 :b 2})
->[1 2 {:a 1 :b 2}]

2
šŸ¤˜ 1
NoahTheDuke 2021-03-18T16:59:46.089900Z

that's cool as hecck

alexmiller 2021-03-18T17:04:47.090500Z

fyi, having some problems with the actual release process so not yet available

pez 2021-03-18T17:19:52.092Z

I get this when trying to run tests in a fresh clj-new library project:

$ clojure -M:test:runner
Error building classpath. Manifest type not detected when finding deps for com.cognitect/test-runner in coordinate {:git/url "git@github.com:cognitect-labs/test-runner.git", :sha "209b64504cb3bd3b99ecfec7937b358a879f55c1"}
What am I not getting?

p-himik 2021-03-18T17:24:49.092600Z

I have a very faint memory of that error. Is your clj up to date?

alexmiller 2021-03-18T17:25:56.092800Z

you probably have an empty dir in your gitlibs directory

alexmiller 2021-03-18T17:26:35.093Z

at ~/.gitlibs/libs/com.cognitect/test.runner/209b64504cb3bd3b99ecfec7937b358a879f55c1

alexmiller 2021-03-18T17:27:21.093200Z

there was some bugs in the recent prereleases that would cause this

alexmiller 2021-03-18T17:27:49.093400Z

you can rm -rf that sha dir and clojure -Sforce -M:test:runner to fix up

pez 2021-03-18T17:30:11.093600Z

Ah, yes, I am still running the prerelease, probably. Sorry for the noice!

alexmiller 2021-03-18T17:33:06.094Z

in that case, you might want to clean your whole ~/.gitlibs when you update

pez 2021-03-18T17:34:26.094200Z

Yes, that did it. Thanks!

pez 2021-03-18T17:40:37.098800Z

I need some ideas on how to test the output from tap> a bit more reliably than I do now. I first thought I was not going to use CI for the project, but now I am doing that anyway and the tests fails intermittently. The docs for tap> tells me that I am probably tapping while there is no room in the queue. The tests all look similar to this:

(testing "Taps the binding box"
    (let [tapped (atom nil)
          save-tap (fn [v] (reset! tapped v))]
      (add-tap save-tap)
      (is (= [:foo :bar]
             (sut/let> [foo :foo
                        bar :bar]
                       [foo bar])))
      (is (= '[[foo :foo]
               [bar :bar]]
             @tapped))
      (remove-tap save-tap)))
Currently I have five of them and when I run the tests from the command line about 1 or 2 fail because I pick up nil from the tapped atom. And sometimes all pass. (The macro let> there taps, maybe I should mention.)

seancorfield 2021-03-18T17:50:30.099Z

@pez Also, if you make a fresh clj-new project, the test runner should be an https URL:

(! 885)-> clojure -X:new :name pez/example
Generating a project called example based on the 'app' template.
(! 886)-> cat example/deps.edn 
{:paths ["src" "resources"]
 :deps {org.clojure/clojure {:mvn/version "1.10.2"}}
 :aliases
 {:run-m {:main-opts ["-m" "pez.example"]}
  :run-x {:ns-default pez.example
          :exec-fn greet
          :exec-args {:name "Clojure"}}
  :test {:extra-paths ["test"]
         :extra-deps {org.clojure/test.check {:mvn/version "1.1.0"}}}
  :runner
  {:extra-deps {com.cognitect/test-runner
                {:git/url "<https://github.com/cognitect-labs/test-runner>"
                 :sha "b6b3193fcc42659d7e46ecd1884a228993441182"}}
...

seancorfield 2021-03-18T17:51:05.099200Z

Maybe you have a rewrite rule in your Git config?

seancorfield 2021-03-18T17:51:48.099900Z

tap&gt; returns true if it succeeds, else false so you can check the result of calling it.

seancorfield 2021-03-18T17:52:55.100700Z

And I expect thereā€™s some concurrency at play: after you tap&gt; something, it may not run the tap watchers ā€œimmediatelyā€ @alexmiller?

nbardiuk 2021-03-18T18:15:03.102200Z

to solve "eventually" called tap watchers try to replace atom with promise . The assertion should use explicit deref with timeout like (deref tapped 100 :timeout)

pez 2021-03-18T18:18:23.102300Z

Nah, I had just been testing some different variants. šŸ˜ƒ

pez 2021-03-18T18:30:29.103700Z

@seancorfield I donā€™t know how to test the return value from the tap&gt;. It happens inside the macro I am testingā€¦

1
pez 2021-03-18T18:33:04.106500Z

@nbardiuk it seems it is not eventually called. Rather it is called and then eventually that succeeds. Also needs to work with CLJS, even if I guess I could use a reader conditional for that.

borkdude 2021-03-18T19:19:06.107700Z

Continuing the thread from #news-and-articles, with clojure 1.11.0 I get:

$ clj -A:clojure-1.11.0
Clojure 1.11.0-alpha1
user=&gt; (let [{:keys [] :as m} {:a 1}] m)
{:a 1}
user=&gt; (let [{:keys [] :as m} [{:a 1}]] m)
[{:a 1}]
user=&gt; (let [{:keys [] :as m} (list {:a 1})] m)
{:a 1}
user=&gt; (let [{:keys [] :as m} (list {:a 1} {:b 2})] m)
{{:a 1} {:b 2}}
Why is there a difference between the second and third example? Because a seq with a map in it, destructured as a map, destructures the first map in the seq? :thinking_face:

2021-03-19T07:04:14.154300Z

Ok, so this is logical actually I believe. Vectors are associatives as well. So if you say destructure associative as m and use m you get back the associative as-is. But sequence are not associative, and when destructured as an associative they are coerced into one. So #3 used to throw because it doesn't have an even number of key/value pairs for the coercion. While in #4 it does so you get a map where the first element in the seq is the key and the second is the value. And with 1.11, sequence of a single or trailing map destructure as an associative of that map. So now in #3 you get single map back.

2021-03-19T07:12:13.155700Z

Though I'm curious, what happens in 1.11 for:

(let [{a :a}
      (list :a 1 :b {:a 2})]
  a)

seancorfield 2021-03-19T16:47:41.171100Z

(! 893)-&gt; clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.11.0-alpha1"}}}'
Clojure 1.11.0-alpha1
user=&gt; (let [{a :a}
      (list :a 1 :b {:a 2})]
  a)
1

borkdude 2021-03-18T19:23:17.108700Z

The third example was previously not working and now works, but isn't intuitive. Maybe should be seen as a side-effect of supporting maps as kwargs?

alexmiller 2021-03-18T19:27:37.109900Z

can you please move questions like this to ask.clojure ?

nilern 2021-03-18T19:31:20.111300Z

Side-effects are bad, looks like a bug to me...

seancorfield 2021-03-18T19:36:27.111400Z

1, 2, and 4 are the same on 1.10.3. 3 is not legal on 1.10.3:

Clojure 1.10.3
user=&gt; (let [{:keys [] :as m} {:a 1}] m)
{:a 1}
user=&gt; (let [{:keys [] :as m} [{:a 1}]] m)
[{:a 1}]
user=&gt; (let [{:keys [] :as m} (list {:a 1})] m)
Execution error (IllegalArgumentException) at user/eval143 (REPL:1).
No value supplied for key: {:a 1}
user=&gt; (let [{:keys [] :as m} (list {:a 1} {:b 2})] m)
{{:a 1} {:b 2}}

seancorfield 2021-03-18T19:36:58.111600Z

So there already was a difference between 2 and 3.

seancorfield 2021-03-18T19:37:31.111800Z

@nilern FYI since you thought it was a bug.

borkdude 2021-03-18T19:40:03.112200Z

all Clojure-related questions should now be posted to ask.clojure instead of here?

alexmiller 2021-03-18T19:40:28.112800Z

concrete questions that might be bugs can more usefully be asked there where they can be tracked

alexmiller 2021-03-18T19:40:54.113100Z

conversational questions are probably better asked here

borkdude 2021-03-18T19:41:06.113500Z

This was intended as the latter, just exploring the new patch

borkdude 2021-03-18T19:41:17.113800Z

The example came more or less directly from the tests

nilern 2021-03-18T19:42:14.114100Z

Okay more like it is an opportunity to create bugs by writing a map pattern and giving it a seq where one of those was a mistake and then it just works but ignores the rest of the seq

2021-03-18T19:48:42.115900Z

The tests are there to check certain behaviors do what they're supposed to do. In practice no one directly destructures a seq with an associative form in a let.

2021-03-19T13:14:35.163500Z

it does work

šŸŽ‰ 1
borkdude 2021-03-18T19:49:17.116700Z

Another question about the patch: There was a core function introduced, but never used but anywhere in the tests. However, in destructure this same pattern as the core function was used. Wasn't the new core function used because of performance (inlining), but still exposed for people who want to implement their own kind of destructuring?

2021-03-18T19:50:04.117600Z

I think the function is in the tests no? But yes, your instinct about why it was exposed.

borkdude 2021-03-18T19:50:05.117700Z

Understood. The test just confused me.

user=&gt; (let [[&amp; {:keys [] :as m}] (list {:a 1})] m)
{:a 1}
would have been more intuitive to me.

borkdude 2021-03-18T19:50:48.118400Z

yes, it was never used "anywhere but in the tests" (placed the word /but/ in the wrong place)

borkdude 2021-03-18T19:51:19.118700Z

Thanks for clearing that up.

2021-03-18T19:52:47.120300Z

Also, it wasn't used in destructure not because of the speed of inlining but because emitting a call to a function that only exists in 1.11 isn't backwards compatible.

borkdude 2021-03-18T19:52:49.120400Z

In fact, I am implementing my own destructure, so I will jump on that new core fn now :)

borkdude 2021-03-18T19:52:58.120600Z

Good point!

nilern 2021-03-18T19:57:42.122300Z

I like it when tools prevent me from shooting myself in the foot but I guess Clojure has always been more in the "power tools" category

2021-03-18T19:59:36.123Z

What errors are you hoping that Clojure helps you with in this case?

emccue 2021-03-18T20:06:39.126300Z

Has anyone been able to make lein ring serve over http/2? Specifically I have a part of my app that is loading a bunch of static files at once and the dev time performance is abysmal

seancorfield 2021-03-18T20:06:47.126700Z

He is concerned that code which used to blow up if you made a mistake now does something, so if you accidentally try to destructure a sequence against a map you get an (unexpected) result now whereas you used to get an exception. Is that accurate @nilern?

alexmiller 2021-03-18T20:10:28.127900Z

this is a tradeoff we have repeatedly considered and made in the design of clojure, in favor of giving users more power (see transducer arities for another example)

ā˜ļø 1
borkdude 2021-03-18T20:11:11.128800Z

@fogus FYI, I backported the new core fn to 1.10 and it seems to work even without the new Java stuff that got added in createAsIfByAssoc. Using it in sci's destructure:

$ ./bb -e '(defn foo [&amp; {:keys [:a :b] :as m}] [a b m]) (foo {:a 1 :b 2})'
[1 2 {:a 1, :b 2}]

šŸŽ‰ 7
nilern 2021-03-18T20:17:09.130700Z

I would have expected the change to only affect rest params. But now that I think of it that would be inconsistent, which I don't like either šŸ¤·

pez 2021-03-18T20:25:21.130900Z

Actually this probably is in the right direction. I couldnā€™t get it to work, because I didnā€™t really know how to do it. But adding a short pause between tapping and untapping makes it work.

#?(:cljs (set! *exec-tap-fn* (fn [f] (f))))

(def tapped (a/chan (a/sliding-buffer 1)))
(def save-tap (fn [v] (a/offer! tapped v)))

(deftest let&gt;
  (testing "Evaluates as `let`"
    (is (= [:foo :bar] (sut/let&gt; [foo :foo
                                  bar :bar]
                                 [foo bar]))))

  (testing "Taps the binding box"
    (add-tap save-tap)
    (is (= [:foo :bar]
           (sut/let&gt; [foo :foo
                      bar :bar]
                     [foo bar])))
    #?(:clj (a/&lt;!! (a/timeout 10)))
    (is (= '[[foo :foo]
             [bar :bar]]
           (a/poll! tapped)))
    (remove-tap save-tap))
...

borkdude 2021-03-18T20:26:24.131600Z

Ah I see. Only the ((partial addn 100 :a 1) {:b 2}) tests still fail on Clojure 1.10.x with this backport. Will be automatically fixed for whoever uses sci with Clojure 1.11.1.

pez 2021-03-18T20:27:16.131900Z

(Probably would have worked with the atom as well, but I had already switched to channels and it does make for less boilerplate so I let it be like that.)

borkdude 2021-03-18T20:31:08.133200Z

Arguably transducers could have lived in separate similarly named functions without losing any power, unless I'm missing something (which is very likely). E.g. mapping, filtering, etc. But that ship has long sailed.

2021-03-20T16:56:48.260300Z

As a side note, I too enjoy the ā€™ing qualifier/naming convention for transducers - so expressive and meaningful.

imre 2021-03-18T20:37:52.133600Z

On that note, could you imagine a linter that warned on usages of the lazy arities of those core fns? I find myself looking for those in PRs

borkdude 2021-03-18T20:38:34.133800Z

you mean, force users to use transducers?

borkdude 2021-03-18T20:38:45.134Z

that doesn't seem a good idea?

Craig Brozefsky 2021-03-18T20:42:20.134700Z

been away from JSON parsing a bit, but is cheshire still the goto?

Craig Brozefsky 2021-03-18T20:42:29.134900Z

err, a goto 8^)

nilern 2021-03-18T20:43:37.135Z

Maybe (-&gt;&gt; stuff (map inc) (filter even?) (into #{})) type of thing which I too optimize quite often

nilern 2021-03-18T20:44:53.135300Z

https://github.com/metosin/jsonista is faster and the API is less crufty

nilern 2021-03-18T20:45:42.135600Z

But Cheshire seems still more common and I am actually working on a PR to it as we speak

Craig Brozefsky 2021-03-18T20:47:28.135800Z

Much appreciated! thanks.

imre 2021-03-18T20:48:39.136Z

Not forcing, just nudging. But at least in our case laziness is rarely if ever justified, and the overhead is a lot less using transducers

alexmiller 2021-03-18T20:55:52.136200Z

data.json is rapidly getting faster thx to @slipset ...

slipset 2021-03-18T21:00:01.136400Z

Depending on the use-case, (for rest, payloads around 1k with shallow maps) data.json is at the same speed as at least Cheshire now. When payloads get bigger, data.json suffer a bit, but not all that much. I havenā€™t worked that much on writes yet, but Iā€™ve gotten some fairly nice speedups there as well. Regarding crufty api, was that for cheshire or data.json, and if data.json, what do you find crufty about the api? Iā€™m curious since Iā€™m working in that area now (not saying the api will change, just interested).

seancorfield 2021-03-18T21:03:30.137600Z

@alexmiller FWIW, our entire test suite passes at work on Clojure 1.11.0 Alpha 1 (on a combination of OpenJDK 8 and OpenJDK 15 for various apps).

šŸ‘ 8
5
2021-03-23T19:36:39.378900Z

This is awesome!

seancorfield 2021-03-23T19:55:25.379100Z

We also just merged a bunch of changes on dev to actually take advantage of the new feature by simplifying a lot of apply / apply concat / (into [] cat ..) style code that was dealing with named arguments being passed around.

2021-03-23T20:04:03.379700Z

You're not a bit worried that this release is meant for "early feedback" on the feature which could mean breaking changes?

seancorfield 2021-03-23T20:17:22.379900Z

Weā€™ve run alpha builds of Clojure in production since 2011. Sometimes weā€™ve had to revert a few early changes, but itā€™s very rare.

šŸ¤Æ 1
šŸ’Ŗ 1
šŸ‘Œ 1
borkdude 2021-03-18T21:05:35.137700Z

Meanwhile @nilernā€™s PR to speed up encoding of cheshire with 15% was merged :)

borkdude 2021-03-18T21:05:51.137900Z

by replacing doseq with reduce, haha

borkdude 2021-03-18T21:08:36.138300Z

On the topic of JSON/jackson, don't the same arguments of trying to avoid jackson apply to transit-java?

alexmiller 2021-03-18T21:10:35.138500Z

for data.json, having no deps is a primary goal. for transit, performance is a higher priority (but I'd love for it to lose it's deps too)

borkdude 2021-03-18T21:10:50.138800Z

Or are there any plans to move transit to data.json eventually?

alexmiller 2021-03-18T21:11:12.139Z

well note that transit-java is java and having it depend on data.json (clojure) is maybe weird

slipset 2021-03-18T21:11:29.139200Z

For the more significant speedups, all of these libs spend a significant amount of time calling assoc! , so I got some code where I wrap a java map so it looks like a persistent map. Iā€™m currently looking into wrapping java lists so it looks like a persistent vector, but couldnā€™t find the exact interfaces I needed to implement.

alexmiller 2021-03-18T21:12:02.139400Z

I'm not convinced any of that is a good idea :)

slipset 2021-03-18T21:12:04.139600Z

(but for reference, for payloads above 10b data.json (and cheshire) seem to be spending about 60% of their time calling assoc!)

borkdude 2021-03-18T21:12:07.139800Z

true. Recently jackson was bumped for cheshire related to a security thing. Would transit-java also be open to such a bump if there was a security risk (or just for keeping up with the ecosystem)?

alexmiller 2021-03-18T21:12:19.140100Z

yes, of course

alexmiller 2021-03-18T21:13:00.140300Z

I think the issue with transit-java is that it is on a pretty old version of jackson and there have been some (many?) breaking changes in the intervening time so it's a non-trivial change

alexmiller 2021-03-18T21:13:15.140500Z

if I remember correctly from the last time I looked at it

nilern 2021-03-18T21:13:17.140700Z

I meant Cheshire, which has parse-string parse-string-strict, parse-stream, parse-stream-strict etc. and cannot parse InputStream even though Jackson can... while Jsonista just has read-value with protocol dispatch.

šŸ‘ 3
alexmiller 2021-03-18T21:13:27.140900Z

but putting this in a transit-java issue is the best place for it (there may be one)

borkdude 2021-03-18T21:14:15.141300Z

@alexmiller FYI I am running cheshire and transit within the same project(s) and never saw an issue so far

alexmiller 2021-03-18T21:15:28.141600Z

well, that's good to know, put all that in a transit-java issue :)

slipset 2021-03-18T21:15:50.141800Z

We have exclusions on jackson in our project-clj (for whatever reason)

seancorfield 2021-03-18T21:27:32.142400Z

I expect weā€™ll take it to production next weekā€¦

borkdude 2021-03-18T21:43:31.142700Z

Ah, the Jackson CVE is only relevant to cbor which isn't used in transit-java, so I would not have a good case to bump it in that lib

borkdude 2021-03-18T21:44:56.143Z

But according to their docs, newer minor versions should not break libs using older ones: https://github.com/FasterXML/jackson/wiki/Jackson-Releases#general

borkdude 2021-03-18T21:46:09.143200Z

(with a caveat about deprecated methods)