beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
roelof 2021-01-25T08:52:45.239200Z

hmm, seeing something really wierd

roelof 2021-01-25T08:53:16.239900Z

I installed cljs but when I want to use it , it not found

roelof@DESKTOP-GKSR5BK:~/learn-reagent-course-files/giggin$ yarn global add shadow-cljs
yarn global v1.22.5
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...

success Installed "shadow-cljs@2.11.14" with binaries:
      - shadow-cljs
Done in 0.81s.
roelof@DESKTOP-GKSR5BK:~/learn-reagent-course-files/giggin$ shadow-cljs -h
shadow-cljs: command not found

solf 2021-01-25T08:57:28.240Z

That's off-topic, as it's nodejs/yarn related. You can try yarn global bin, that will show you where yarn puts the binaries it installs, and then check that folder is in your $PATH https://classic.yarnpkg.com/en/docs/cli/global/

roelof 2021-01-25T09:04:41.240400Z

thanks

Yang Xu 2021-01-25T09:41:48.247500Z

Hi, I need to write a method to complete data interaction when I invoke Clojure from Java. The detail of the problem is I need to convert the key and value of HashMap to the keyword, and HashMap has a hierarchy nested, maybe ArrayList, HashSet, or HashMap. I wrote the code below, but it didn’t work. So who can tell me how should I do?

(defn keywordize-kv [m]
  (println (let [f (fn [[k v]] [(if (string? k) (keyword k) k) (if (string? v) (keyword v) v)])]
             (walk/postwalk (fn [x] (cond
                                      (instance? java.util.HashMap x) (into {} (map f x))
                                      (instance? java.util.HashSet x) (into #{} (map f x))
                                      (instance? java.util.ArrayList x) (into [] (map f x))
                                      :else x))
                            (into {} m)))))

Yang Xu 2021-01-28T06:25:43.026100Z

Wow, Thank you for so much advice, I change my code to below. It worked, and I think I should predefined API to implement data interaction of Java with Clojure.

(defn keywordize-kv [m]
  (let [f (fn [[k v]] [
                       (if (string? k) (keyword k) k)
                       (cond (string? v) (keyword v)
                             (instance? java.util.HashSet v) (into [] (map (fn [x] (if (string? x) (keyword x) x)) v))
                             (instance? java.util.ArrayList v) (into [] (map (fn [x] (if (string? x) (keyword x) x)) v))
                             )])]
    (walk/postwalk (fn [x] (if (map? x) (into {} (map f x)) x)) (into {} m))))

caumond 2021-01-25T10:09:55.251300Z

Hi, I find solutions but all really verbose and not idiomatic: I have an atom with a list of element, the list is not huge but will have some hundreds of elements.

(def i (atom (list {:a 3} {:a 2} {:a 5})))
(defn dequeue [atom-list-evt pred]
????)
(dequeue i (comp even? :a))
; --> {:a 2}
@i
;; -> '({:a 3} {:a 5})
I would like to write that dequeue function to return the first element in the list matching pred, and I expect that dequeue function to update the atom, dropping the element which has been returned.

raspasov 2021-01-25T10:33:01.251500Z

@caumond a few points: 1. lists are not super idiomatic in Clojure 2. lists only support efficient adding/removing at the start of the list; that might not matter too much (like you said, a few hundred elements might be OK to recreate on every update if those updates are not too often; still that’s not a very idiomatic thing to do) 3. If you need to efficiently add/remove items based on index/key, perhaps you can consider sorted-map; this would allow you to maintain a queue-like feel with the sorted map’s keys

raspasov 2021-01-25T10:44:31.251700Z

(def a (atom (sorted-map 2 {:a 5} 0 {:a 2} 1 {:a 3})))


(defn dequeue [a pred]
  (let [[k v] (some pred @a)]
    (when v
      (swap! a dissoc k)
      v)))

raspasov 2021-01-25T10:44:32.251900Z

(dequeue a (fn [[k v]] (when (-> v :a even?) [k v])))

raspasov 2021-01-25T10:44:41.252100Z

=> {:a 2}

raspasov 2021-01-25T10:44:58.252300Z

@a => {1 {:a 3}, 2 {:a 5}}

caumond 2021-01-25T11:10:31.252700Z

Ok, I got it. I was confused because the key is "dynamic". Each element I drop will update the maps and their key. I need to think a little bit, but keeping the collection sorted with the sorted-map answer my question I guess. Thx

caumond 2021-01-25T11:11:19.252900Z

But, in your solution, you "scan" the collection twice, one for "some", the other for dissoc, I understand that with sorted map it will be efficient. Aren't we able to do it in one raw? maybe something like split-by?

Christian 2021-01-25T11:34:07.253800Z

Is a library the same as a DSL? I don't really get the difference. I mean the implementation in Clojure.

2021-01-26T10:27:16.365900Z

And then starts to try to explain to you that programming regexes are strictly more expressive 😛 You know, because perl

raspasov 2021-01-25T11:49:25.254100Z

It’s true, we scan the collection in the (some … ) call

raspasov 2021-01-25T11:50:22.255900Z

The (dissoc …) call is effectively constant speed (aka roughly O(1) ) so we can ignore that;

2021-01-25T11:50:48.256500Z

A DSL is a domain specific language, meaning that it is a sublanguage for a more specific purpose. A good example may be SQL, being a DSL for interacting with databases

raspasov 2021-01-25T11:51:58.257900Z

If you need constant scan… we’d need to devise something more clever; but I’d stick with this solution, unless high performance is needed for sure

2021-01-25T11:52:48.259100Z

That said, you can embed a DSL inside another language, for example HoneySQL is a version of the SQL DSL that used clojure data structures as its medium. So the line gets more blurry

raspasov 2021-01-25T11:55:43.259300Z

Excluding things like HoneySQL, which can be described as more or less as 1-to-1 conversion between Clojure data and SQL, when people say DSL in Clojure, they usually mean some considerable use of macros; that’s usually frowned upon, unless a really good reason for the DSL/macro use exists

caumond 2021-01-25T11:56:07.259500Z

Yes, no doubt this simple solution is ok to start. Not sure where the design will lead me, so no need to optimize. I was just trying to understand how we are suppose to do.

raspasov 2021-01-25T11:56:38.259700Z

HoneySQL is great, I think it’s a must use if you need to deal with a SQL database from Clojure

caumond 2021-01-25T11:57:01.259900Z

Thx @raspasov

raspasov 2021-01-25T11:57:59.260100Z

Of course 🙂 “Constant scan” is a sort of a paradox by definition; you cannot really look at many items and expect that to be constant time… without the use of indices/full-text search, etc, etc (all solution involving many more moving parts)

raspasov 2021-01-25T11:59:48.260300Z

One “clever” thing I’ve used in the past is the use of two maps: (def map-1 {:a 1, :b 2, :c 3})

raspasov 2021-01-25T12:00:10.260500Z

(def map-2 {1 :a, 2 :b, 3 :c})

raspasov 2021-01-25T12:00:27.260700Z

Basically two maps that are “inverse indices” of each other

Christian 2021-01-25T12:01:52.260900Z

With the "if you can use a function, don't use a macro" concept, I was wondering if something like HoneySQL is just a bunch of functions (with java interop or something) with the occasional macro. DSL being "helps to deal with sql databases". While any library would be "helps to deal with xy"

raspasov 2021-01-25T12:03:56.261100Z

That can help avoid scanning in some cases… if you’re able to lookup by exact value or key;

raspasov 2021-01-25T12:07:28.261300Z

Right… the definition of DSL is up for interpretation; at least when I hear it, I usually associate it with macros; and macros are rarely used in majority of Clojure libraries, likely for good reasons

raspasov 2021-01-25T12:07:57.261500Z

The (go…) macro from core.async being a big exception

Daniel Stephens 2021-01-25T12:11:12.261700Z

do you need it stateful as opposed to giving back both the popped value and the new seq with the value dropped?

Daniel Stephens 2021-01-25T12:19:24.262800Z

something like this maybe, you could apply the same logic to your atom if you do need the state

(defn dequeue
  [pred coll]
  (let [head (take-while (complement pred) coll)
        [v & tail] (drop (count head) coll)]
    [v (concat head tail)]))

Piotr Brzeziński 2021-01-25T12:20:01.263400Z

Hello 🙂. Is there any example I could view of using speech synthesis in clojurescript? I’ve been trying to follow this https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis but I’m having troubles understanding how to interop with JS classes correctly.

simongray 2021-01-25T12:26:39.263700Z

I think you will have more luck trying to find more general examples of interop. What are you having trouble with?

Piotr Brzeziński 2021-01-25T12:30:57.263900Z

So there`s this part

var utterThis = new SpeechSynthesisUtterance(inputTxt.value);
that then has to be mutated in JS like so
utterThis.pitch = pitch.value;
utterThis.rate = rate.value;
so then I can call
synth.speak(utterThis);
I know I can setup the synth with
(def synth (.-speechSynthesis js/window))
but I fail to understand the utterThispart and then how to call synth.speak(uttherThis)

simongray 2021-01-25T12:37:19.264100Z

(def utterThis (new js/SpeechSynthesisUtterance "some text"))
or
(def utterThis (js/SpeechSynthesisUtterance. "some text"))

simongray 2021-01-25T12:37:44.264400Z

and then

simongray 2021-01-25T12:38:08.265100Z

(.speak synth utterThis)
to call it

Piotr Brzeziński 2021-01-25T12:38:29.265700Z

But the speak method exists on synth

Piotr Brzeziński 2021-01-25T12:38:32.265900Z

This is the part I dont get

simongray 2021-01-25T12:38:43.266300Z

or sorry

Piotr Brzeziński 2021-01-25T12:38:50.266600Z

(-> utterThis .-speak .synth) like that?

Piotr Brzeziński 2021-01-25T12:39:20.267100Z

Oh, interesting.

simongray 2021-01-25T12:39:52.267600Z

when you call a method the first argument is always the object containing the method.

simongray 2021-01-25T12:40:18.268100Z

So the second argument of the call would the first (and only) arg in the JS version.

Piotr Brzeziński 2021-01-25T12:40:23.268400Z

Right, makes sense. So then I get back a method and apply utterThis to it. Nice 🙂

Piotr Brzeziński 2021-01-25T12:40:28.268700Z

Thanks a lot!

simongray 2021-01-25T12:40:43.269Z

np! looks like a fun API. Will need to check it out.

Piotr Brzeziński 2021-01-25T12:41:03.269300Z

Yeah, I want to use it for a simple metronome app.

mloughlin 2021-01-25T12:41:49.269700Z

I've got a bunch of decimal numbers that are represented as vecs of two ints [10 0] => 10.0 . What's the least ridiculous way of adding them together? e.g. (my-add [9 9] [1 2]) ; => [11 1]

simongray 2021-01-25T12:43:43.270200Z

Here’s a full example

(let [utterThis (js/SpeechSynthesisUtterance. "some text")]
  (js/window.speechSynthesis.speak utterThis))

Piotr Brzeziński 2021-01-25T12:44:10.270400Z

Thanks, that helped a lot!

🙏 1
simongray 2021-01-25T12:45:41.270700Z

note that you can use dot as a shortcut directly for both properties and functions, e.g. you can use (js/window.speechSynthesis.speak utterThis) directly so that you in princicple never have to define synth.

👍 1
simongray 2021-01-25T12:57:35.271300Z

(defn my-add [& tuples]
  (let [tuple->float (fn [[n1 n2]] (Double/parseDouble (str n1 "." n2)))]
    (reduce + (map tuple->float tuples))))

Daniel Stephens 2021-01-25T13:03:32.272900Z

do you need to think about negatives? is [-10 5] equal to -9.5 or -10.5, maybe:

(fn add [[t1 d1] [t2 d2]]
  (let [D (+ d1 d2)
        d (rem D 10)
        t (+ t1 t2 (int (/ D 10)))]
    [t d]))
or
(fn add [[t1 d1] [t2 d2]]
  (let [a (+ t1 t2 (/ d1 10) (/ d2 10))]
    [(quot a 1) (* 10 (rem a 1))]))

Ilmari Pohjola 2021-01-25T13:04:30.274400Z

Does anyone know if I need to use Compojure in HerokuApp? I have a very basic "application" in Heroku, which crashes. I'll add the simple code to comments. Error trace shows next lines, which I believe asre important. Picked up JAVA_TOOL_OPTIONS: -Xmx300m -Xss512k -XX:CICompilerCount=2 -Dfile.encoding=UTF-8 2021-01-24T12:54:12.831812+00:00 app[web.1]: Syntax error (ClassNotFoundException) compiling at (ring/util/servlet.clj:1:1). 2021-01-24T12:54:12.831836+00:00 app[web.1]: javax.servlet.AsyncContext

Ilmari Pohjola 2021-01-25T13:05:29.274500Z

Project.clj: (defproject mutable-app "1.0.0-SNAPSHOT"   `:description "FIXME: write description"`   `:url "http://mutable-app.herokuapp.com"`   `:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"`             `:url "https://www.eclipse.org/legal/epl-2.0/"}`   `:dependencies [[org.clojure/clojure "1.10.1"]`                  `[ring "1.8.1"]`                  `[metosin/reitit "0.4.2"]`                  `[metosin/ring-http-response "0.9.1"]`                  `[ring/ring-jetty-adapter "1.2.2"]`                  `[ring/ring-devel "1.2.2"]`                  `[environ "0.5.0"]]`   `:min-lein-version "2.0.0"`   `:plugins [[environ/environ.lein "0.2.1"]]`   `:uberjar-name "mutable-app-standalone.jar"`   `:profiles {`       `:production {:env {:production true}`        `:uberjar {:aot :all}}})`

Ilmari Pohjola 2021-01-25T13:05:49.274800Z

Procfile: web: java $JVM_OPTS -cp target/mutable-app-standalone.jar clojure.main -m mutable-app.web

Ilmari Pohjola 2021-01-25T13:07:53.275Z

Then the following two code files: (ns endpoints (:require [ring.util.http-response :as response])) (def addition ["/addition" {:get (fn [request] (let [params (:query-params request) x (Long/parseLong (get params "x")) y (Long/parseLong (get params "y"))] (response/ok {:total (+ x y)})))}]) (def math-routes ["/math" addition])

(ns mutable-app.web
  (:require
   [ring.adapter.jetty :as jetty]
   [environ.core :refer [env]]
   [ring.middleware.params :as params]
   [reitit.ring.middleware.muuntaja :as muuntaja]
   [muuntaja.core :as m]
   [reitit.ring.coercion :as coercion]
   [reitit.ring :as ring]
   [endpoints]))


(def app
  (ring/ring-handler
   (ring/router
    [endpoints/math-routes]
    {:data {:muuntaja   m/instance
            :middleware [params/wrap-params
                         muuntaja/format-middleware
                         coercion/coerce-exceptions-middleware
                         coercion/coerce-request-middleware
                         coercion/coerce-response-middleware]}})
   (ring/create-default-handler)))

(defn -main [& [port]]
  (let [port (Integer. (or port (env :port) 5000))]
    (jetty/run-jetty #'app {:port  port
                            :join? false})))

Hagenek 2021-01-25T13:45:25.275500Z

Why does this loop not terminate?

(defn sing
  "Given a start and an optional end, returns all verses in this interval. If
  end is not given, the whole song from start is sung."
  ([start]
   (loop [start_num start]
     (when (> start_num 0)
       (println (verse start_num)))
     (recur (- start_num 1))))
  ([start end] (str "You start at " start " and end at " end)))

2021-01-25T13:50:38.275900Z

If it does not terminate then possibly because recur is called unconditionally inside loop

motform 2021-01-25T13:50:44.276100Z

I have not run it, but I belive you are missing any kind of terminating condition. The body of the loop containts a conditinal println with when, after which you recur. Thus, you will always recur. If you want to terimnate, you might want to use an if. Also, if you are looping over a number to perform side effects, it is common to use dotimes. https://clojuredocs.org/clojure.core/dotimes

tvirolai 2021-01-25T13:53:51.276400Z

Yep, check your parentheses. Also, as a linter would probably notify, check out the pos? and dec functions

caumond 2021-01-25T14:31:27.276700Z

if I understand well, this solution has an assumption that the collection is sorted, with values satisfying the predicate first.

Daniel Stephens 2021-01-25T14:33:18.276900Z

(dequeue #(> % 5) (range 10))
=> [6 (0 1 2 3 4 5 7 8 9)]
nope, also nice and lazy (at least for elements after the first truthy value)
(first (dequeue #(> % 1000) (range)))
=> 1001

caumond 2021-01-25T14:34:22.277200Z

ok ok, so sorry, I thought I was clojure fluent, ...

☺️ 1
caumond 2021-01-25T14:34:25.277400Z

lol

mloughlin 2021-01-25T14:54:48.277800Z

Thanks both, that's given me a something to think about! I don't need to bother with negatives, it's a business rule where the numbers are between 0.0 and 10.0 and max 1 decimal place after the point.

Dave Russell 2021-01-25T15:26:54.281700Z

Is it possible to have spec check the validity of non-namespaced keywords that are not declared in an s/keys map? For example, you can define:

(s/def ::foo int?)
(s/def ::myspec (s/keys))
Such that (s/valid? ::myspec {::foo :bad-non-int}) will fail. But I want it to fail even for the non-namespace keyword {:foo :bad-non-int}

alexmiller 2021-01-25T15:36:55.282Z

no, not like that

alexmiller 2021-01-25T15:37:38.282400Z

I mean, you can use (s/keys :opt-un [::foo])

Hagenek 2021-01-25T15:41:01.283400Z

When working with the clojure test library, is it possible to get it to give you the explicit values it is comparing against? I get this, which is not very useful for finding small errors in strings: FAIL in (test-song) (beer_song_test.clj:47) expected: (= song-3-0 (beer-song/sing 3)) actual: (not (= "3 bottles of beer on the wall, 3 bottles of beer.\nTake one down and pass it around...))

Dave Russell 2021-01-25T15:46:39.283500Z

Then I would have to specify it 🙂 But I guess maybe there's no sane way to auto-namespace keywords that aren't explicitly specified via :req-un or :opt-un

Dave Russell 2021-01-25T15:47:09.283700Z

The use-case is that I'm using specs to auto-generate swagger docs and wanted to hide a keyword by just removing it from the spec. I'll opt to post-process the generated swagger instead. Thanks!

dpsutton 2021-01-25T15:48:11.284100Z

isn't that what the actual: line is doing?

dpsutton 2021-01-25T15:48:26.284200Z

user=> (t/deftest foo (t/is (= "bob" "rob")))
#'user/foo
user=> (foo)

FAIL in (foo) (NO_SOURCE_FILE:1)
expected: (= "bob" "rob")
  actual: (not (= "bob" "rob"))
nil
user=>

👍 2
dpsutton 2021-01-25T15:48:48.284400Z

"bob" is the expected and it was given "rob". (not (= "bob" "rob"))

tws 2021-01-25T15:57:35.284700Z

I can tell you’re doing the exercism-clojure problems. this is completely unreadable, but I really liked my golfing solution to beer-song:

(defn verse [count]
  (let [next-count (if (zero? count) 99 (dec count))]
    (cl-format nil "~[No more~:;~:*~D~] bottle~:P of beer on the wall, ~
                    ~:*~[no more~:;~:*~D~] bottle~:P of beer.~%~
                    ~:*~[Go to the store and buy some more~:;Take ~:*~[~;it~:;one~] down and pass it around~], ~
                    ~[no more~:;~:*~D~] bottle~:P of beer on the wall.~%"
               count next-count)))

(defn sing
  ([from] (sing from 0))
  ([from to] (join "\n" (map verse (range from (dec to) -1)))))

2
Hagenek 2021-01-25T16:10:16.285200Z

Thanks a lot! 😃

Hagenek 2021-01-25T16:29:05.286300Z

I guess I am looking for it to print expected: "3 bottles of whiskey on the wall...." actual: "3 bottles of beer on the wall..."

mloughlin 2021-01-25T17:00:34.292700Z

Is there a function in core that lets me call distinct but with a predicate or similar? I have a sequence of maps where some are identical except for one value (of the same key each time). I want to discard them when the rest of their values are the same.

dpsutton 2021-01-25T17:06:52.293500Z

there's a library called medley which has a distinct-by function. You could grab that dep or perhaps just copy and attribute the code for that particular function if license allows

1
1
Hagenek 2021-01-25T17:17:35.294100Z

Wow! That's pretty crazy! I ended up with this: (_defn_ sing   `"Given a start and an optional end, returns all verses in this interval. If`   `end is not given, the whole song from start is sung."`   `([start]`    `(s/join (add-newline (reverse (map verse (range (inc start)))))))`   `([start end] (s/join (add-newline (reverse (map verse (range end (inc start))))))))`

2021-01-25T17:20:31.294400Z

postwalk simply does not work on types other than the standard clojure collections:

ins)user=> (def l (doto (java.util.ArrayList.) (.addAll ["a" "b"  "c"])))
#'user/l
(ins)user=> l
["a" "b" "c"]
(ins)user=> (clojure.walk/postwalk (fn [el] (if (string? el) (keyword el) el)) l)
["a" "b" "c"]

2021-01-25T17:20:46.294600Z

it treats that list as a single thing it doesn't know how to process

2021-01-25T17:22:55.294800Z

prewalk on the other hand can do the transform on the way down, which means it can navigate the structure

(ins)user=> (clojure.walk/prewalk (fn [el] (cond (instance? java.util.ArrayList el) (into [] el) (string? el) (keyword el) :else el)) l)
[:a :b :c]

2021-01-25T17:23:07.295Z

you shouldn't need that into call on the last line

2021-01-25T17:23:52.295200Z

also,`f` will break on things that are not k/v pairs (things that are not elements of hash maps)

2021-01-25T17:27:14.295600Z

@dstephens the problem with that function is it doesn't work with atom thread safety

2021-01-25T17:27:51.295900Z

(but a version of it using compare-and-set! on an atom instead of swap! is possible)

2021-01-25T17:29:56.296200Z

many clojure dsls use raw data instead of macros - eg. the hiccup dsl

2021-01-25T17:31:40.296400Z

another example of a common DSL is regex, which clojure has a reader for but is usually indistinguishable from a string

2021-01-25T17:32:31.296600Z

for binding bodies are a DSL (thanks to :while / :when / :let syntaxes)

caumond 2021-01-25T17:32:50.296800Z

@noisesmith, why not compatible N

2021-01-25T17:35:48.297100Z

I think the key is that most libraries use the language's existing syntax and semantics to solve domain problems DSLs on the other hand introduce a new syntax and/or a new semantics (hiccup reuses clojure's existing syntax but impose a new semantics, for / doseq introduce a new syntax, regex has special reader rules) - they become a new language you need to learn in some meaningful way (even if it's only a couple of rules), and they make the implicit promise that your problem is easier to solve in that language.

🙌 1
2021-01-25T17:36:59.297800Z

core.match and core.logic are good examples of DSLs for clojure - the code written with those libraries isn't readable / intelligible until you learn the DSL used

2021-01-25T17:38:43.299900Z

in my work experience both macro based and data structure based DSLs are looked at with some skepticism - they introduce a barrier to understanding the code, and sometimes they require more work than the convenience they offer (especially with larger teams)

👆 1
2021-01-25T17:39:12.300400Z

even regex tends to be minimized / simplified and replaced with more normal looking building blocks

tws 2021-01-25T17:39:26.300600Z

it is common practice to have your [1-arity with default] version call your other one with the default, avoiding the duplication in there

tws 2021-01-25T17:40:00.301400Z

like i did in the

(defn sing
  ([from] (sing from 0))
...

✅ 1
Hagenek 2021-01-25T17:40:06.301800Z

Yeah, I saw some other solutions after delivering, and have already fixed that! 😃 Thanks

tws 2021-01-25T17:40:12.302100Z

and yes, cl-format is super powerful and arcane

2021-01-25T17:40:17.302400Z

because the value returned by swap! is the value held in the atom, and doing two different ops on an atom to provide one result isn't thread safe

Hagenek 2021-01-25T17:40:27.302800Z

cl-format looks like wizardry alright

Hagenek 2021-01-25T17:40:37.303100Z

😂

tws 2021-01-25T17:40:38.303300Z

pages of docs

2021-01-25T17:40:48.303700Z

Hi everyone, I'm having problem transforming java objects to clojure maps. Where normally calling the bean function would work, I'm getting an empty map :

(-> consumer-record clojure.java.data/from-java) => {}
  (-> consumer-record bean keys) => {:class org.apache.kafka.clients.consumer.ConsumerRecord} 
Calling .key and .value on the consumer record returns the desired data. Also is there a more performant way of transforming such java objects to clojure maps ? thanks a lot in advance

2021-01-25T17:47:20.303900Z

also, if you check for the interfaces (`java.util.Map`, java.util.Set, java.util.List ) instead of the concrete classes, it will behave the same on your enumerated cases, but also be more general for other collection types

Daniel Stephens 2021-01-25T18:01:10.305Z

@noisesmith nothing in that code snippet I posted was for an atom, however as far as I know it would be thread safe to do the following using swap! (which then uses compareAndSet underneath in a loop).

(defn dequeue
  [pred coll]
  (let [head (take-while (complement pred) coll)
        [v & tail] (drop (count head) coll)]
    [v (concat head tail)]))

(defn dequeue-atom
  [pred a]
  (-> (swap! a (fn [c] (let [[v next-c] (dequeue pred c)]
                         (vary-meta next-c assoc :popped v))))
      meta
      :popped))
but I failed to make the point I was trying to which was that unless an atom is really necessary, I'd avoid it entirely!

2021-01-25T18:08:45.305300Z

I'm aware that swap! uses compareAndSet, but using clojure's compare-and-set! is less hacky than using metadata

(defn dequeue-atom
   [pred a]
   (let [v @a
         [res new-coll] (dequeue pred v)]
     (if (compare-and-set! a v new-coll)
       res
       (recur pred a))))

👍 1
2021-01-25T18:09:35.305500Z

@dstephens excellent point that it's better to avoid using an atom at all

caumond 2021-01-25T18:12:01.305800Z

yes!! I thought it would be the first answer on slack: don't do atoms !!

caumond 2021-01-25T18:12:14.306Z

as few as possible

✔️ 1
caumond 2021-01-25T18:13:53.306300Z

but this atom will replace my database... the persistance until I push it on a real database

2021-01-25T18:20:47.306500Z

and how's this for meta: in the mathematical vocabulary, each regex individually describes a language

🤯 1
Daniel Stephens 2021-01-25T18:28:31.306700Z

ConsumerRecord's aren't beans so the default reflection based things won't work. from-java is super helpful here as it's a defmulti that dispatches on class type, so you can just extend it with your custom conversion, e.g.

(defmethod clojure.java.data/from-java ConsumerRecord
  [^ConsumerRecord cr]
  {:topic (.topic cr)
   :key (.key cr)
   :value (.value cr)})
=> #object[clojure.lang.MultiFn 0x7506874e "clojure.lang.MultiFn@7506874e"]
(clojure.java.data/from-java (ConsumerRecord. "topic" 0 0 "key" "value"))
=> {:topic "topic", :key "key", :value "value"}

Daniel Stephens 2021-01-25T18:29:29.306900Z

this is probably close to as performant as you'll get as well, since you can tell clojure the types it's dealing with so it can avoid any reflection (afaik)

NPException 2021-01-25T18:34:38.307100Z

Is from-java a function that already exists somewhere in Clojure? It doesn't seem to be part of the clojure.core namespace.

NPException 2021-01-25T18:35:09.307300Z

Ignore me. I should have read your code example in detail. 😄

2021-01-25T18:38:43.307800Z

Thanks a lot @dstephens

🎉 1
bschup 2021-01-25T18:51:52.311600Z

Just getting started with VSCode clover extension, socket repl, and reveal. I can evaluate code in the editor and see an appropriate result in the clover repl tab, I expect to see similar output in external reveal window but no. I do however see output in the reveal window when evaluating something similar to (tap> (+ 2 2)).

Joe 2021-01-25T18:56:59.314200Z

I don’t know if this is the ‘right’ way, but I set up a custom shortcut to tap block. Or actually I copied Sean Corfield’s shortcuts, which are on GitHub.

bschup 2021-01-25T19:00:30.314400Z

Ah, OK thanks for the tip, will take a look at Sean's key bindings.

seancorfield 2021-01-25T19:00:53.314600Z

@schupbach Yup, you need my key bindings (and config file too).

seancorfield 2021-01-25T19:01:18.314800Z

If you get stuck, ask in #chlorine (Clover is the "same" as Chlorine).

bschup 2021-01-25T19:32:48.315Z

Yeah that did the trick, thanks!

GGfpc 2021-01-25T19:48:10.317200Z

Hello! I'm trying to convert a piece of code from clj-http to clj-ajax because I want to use it in a cljs file. However I'm struggling to get the same result This clj-http code was this

(defn handle
  [request]
  (println (first request)))(defn get-game-data
                              "Fetches the game data from the Lichess API"
                              [user-id]
                              (let [url (str BASE_URL user-id)
                                    request-headers {:headers      {:accept "application/x-ndjson"}
                                                     :query-params {:max 500}}]
                                (-> (client/get url request-headers))))
And this is the cljs-ajax
(defn handle
  [request]
  (println request))

(defn get-game-data
  "Fetches the game data from the Lichess API"
  [user-id]
  (let [url (str BASE_URL user-id)
        request {:headers {"Accept" "application/x-ndjson"}
                 :params  {:max 500}
                 :handler handle}]
    (GET url request)))
The thing with the latter is that the handle function only prints
#object[org.apache.http.nio.entity.ContentInputStream 0x1732b20d org.apache.http.nio.entity.ContentInputStream@1732b20d]
Not sure how to proceed

2021-01-25T19:50:46.317900Z

how is cljs returning an apache http nio?

2021-01-25T19:52:38.318900Z

anyway, you should expect an AJAX method to return a js promise, or allow a callback to be called when the request completes, this is needed because js is single threaded and otherwise you would freeze the page

2021-01-25T19:53:24.319600Z

I've only used AJAX directly via interop, providing a callback or using the promise it returns is relatively straightforward

GGfpc 2021-01-25T19:54:35.320300Z

Yes, the handle function is the callback, it's the handle function that prints the ContentInputStream that is passed to it

2021-01-25T19:56:35.320900Z

if that's actually cljs code, my first guess is that your request handler on the server is broken, and your serializer is "doing its best"

2021-01-25T19:57:26.321500Z

because I have no idea how a java class would show up in the browser

GGfpc 2021-01-25T20:04:31.322200Z

I don't control the server, but if helps this is a cljc file and I'm running it in a cljs nrepl using Cursive

2021-01-25T20:06:55.323300Z

if the lib is cljc compatible, the simplest explanation is that the repl running this code is actually clj (try doing something cljs specific like (js/console.log "foo"))

Scott Starkey 2021-01-25T21:17:39.328600Z

Hi folks - I have a beautiful program that uses Java interop — it allows a user to select a csv file, and outputs an newly processed file. Works in my Doom Emacs REPL. I made a Lein uberjar of it, and it works on my dev machine (Mac). I have tested the Jar file on my other machine, a Windows machine, and program death. (“Well it’s Windows. There’s your problem right there!“)

c:\test>java -jar filter-program-0.1.0-SNAPSHOT-standalone.jar
Exception in thread "main" java.lang.IndexOutOfBoundsException: Invalid index
        at javax.swing.DefaultRowSorter.convertRowIndexToModel(Unknown Source) 
[20 lines of error codes deleted.]
Any thoughts why an uberjar would work one place and not another?

2021-01-25T21:20:23.328900Z

Different version of Java installed on the Windows machine?

Scott Starkey 2021-01-25T21:20:40.329200Z

Hmmm… Let me double check versions.

Daniel Stephens 2021-01-25T21:21:44.329500Z

Not familiar with cljs so may well have missed the point here but have you tried (println (slurp request))

Mno 2021-01-25T21:22:10.330100Z

I would’ve guessed that as well.. since that’s the JVM promise

Scott Starkey 2021-01-25T21:22:14.330300Z

Mac: java version “1.8.0_201” Windows: java version “1.8.0_221"

Mno 2021-01-25T21:23:06.331Z

That gap doesn’t seem big enough to cause it..

Scott Starkey 2021-01-25T21:23:42.332Z

Should I update my Mac environment, just to be sure?

Mno 2021-01-25T21:24:30.332900Z

Same CSV? Also I’ve had issues in the past where the parsers take into account the locale of the computer they’re running on.. (and prefer : over , or even TAB )

Mno 2021-01-25T21:25:32.334600Z

I really doubt it could be that minor version, but if you’ve ruled out everything else, might as well try?

Scott Starkey 2021-01-25T21:25:35.334700Z

Same CSV, but on the Windows machine it never gets as far as that. It displays the window (frame) but dies before it pulls up the dialog box for the user.

Mno 2021-01-25T21:26:54.335600Z

Very strange… hopefully someone smarter/more experienced has more ideas.

❤️ 1
2021-01-25T21:27:24.336500Z

could this be somehow related to windows character encoding config, leading to strings of the wrong length then leading via some set of dominos to looking for a column in the UI that doesn't exist?

Scott Starkey 2021-01-25T21:33:11.338Z

Here’s the exception thread, if that would be helpful.

seancorfield 2021-01-25T21:34:35.339200Z

@scotto Do you do any filesystem path manipulation in your code? Windows uses C:\path\like\this but macOS/Linux are /path/like/this. Or perhaps you assume \n is end of line rather than potentially \r\n on Windows?

2021-01-25T21:34:38.339300Z

what's going on around like 136 of your file?

seancorfield 2021-01-25T21:34:53.339600Z

That was going to be my next question 🙂

Scott Starkey 2021-01-25T21:35:52.340300Z

Line 136:

(.setCurrentDirectory fc (File. (System/getProperty "user.home")))

Daniel Stephens 2021-01-25T21:36:50.340800Z

are you doing things in the correct thread (see bottom of) https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6637181 https://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html

seancorfield 2021-01-25T21:37:00.341100Z

Looks like Clojure needs to use reflection on that line -- and that is somehow wired up to some Swing UI?

Scott Starkey 2021-01-25T21:37:26.341900Z

fc is (def fc (JFileChooser.))

seancorfield 2021-01-25T21:37:55.342900Z

Oh, OK.

Nassin 2021-01-25T21:38:08.343400Z

are you passing in the same CSV file in both cases?

Scott Starkey 2021-01-25T21:38:10.343600Z

Thanks Daniel - I’ll look into that!

🤞 1
Nassin 2021-01-25T21:38:15.343900Z

looks like a programming error

Scott Starkey 2021-01-25T21:38:45.344800Z

I create a new output file to write to. I use Clojure Data CSV, using almost the exact format of their lazy reader/writer example. https://github.com/clojure/data.csv/

2021-01-25T21:42:05.345900Z

Try editing line 136 to get the user.home property first, print it out, and then use it to set the current directory, maybe that’ll tell you something.

👍 1
Scott Starkey 2021-01-25T21:42:38.346300Z

Will do.

alexmiller 2021-01-25T22:10:17.347Z

it's possible for user.home to be null

alexmiller 2021-01-25T22:11:52.347600Z

if it is, that makes that File. constructor a reflective, unresolveable call

alexmiller 2021-01-25T22:13:06.347900Z

although that doesn't match that stack trace

borkdude 2021-01-25T22:23:15.348300Z

can't repro that:

user=> (defn bar [] (java.io.File. (System/getProperty "user.home")))
#'user/bar
user=> (bar)
#object[java.io.File 0x48535004 "/Users/borkdude"]
user=> (defn bar [] (java.io.File. (System/getProperty "user.homex")))
#'user/bar
user=> (bar)
Execution error (NullPointerException) at java.io.File/<init> (File.java:278).
null

sova-soars-the-sora 2021-01-25T23:36:16.349100Z

Hi I'm using a wrapper over google translate... it works great but I'm not sure if I can hide a warning that google translate produces each time:

com.google.cloud.translate.TranslateOptions <init>
WARNING: Ignoring Application Default Credentials GOOGLE_APPLICATION_CREDENTIALS: using explicit setting for API key instead.

2021-01-26T17:13:02.385200Z

> How would one hide the warnings from a specific namespace or package? this is possible with multiple tools, but the universal answer is "via config" - you actually have to sort out which logging backend + adaptors work for your code plus the deps you pull in (I wish I had a satisfying universal answer, but it's just been a "find the dirty hack that works with this codebase" kind of thing)