Fork me on GitHub
#beginners
<
2021-08-02
>
popeye05:08:28

I have an existing req as (GET "/:client_id/client_page")[client_id](get_Client_info client_id), and I want to add optional parameter old_client_id=all how can I append in the get request to obtain optional parameter, I am using compojure

indy13:08:24

You can pass it as a query param? And get the old_client_id just like you get client_id ?

indy13:08:34

Just like greeting is taken as a query param in the above docs, you can take the old_client_id

indy13:08:19

As an aside, you can look at versioning your APIs if the consumers used to pass in the old_client_id in place of the new one

indy13:08:42

You can avoid any ambiguity

popeye14:08:30

I have used :`query-parameter` which takes the optional value

popeye14:08:00

I have a sequence as below ({:data ({:clientId 870, :Id 1})} {:data ({:clientId 555, :Id 3})}) how can merge seqence to get the result like ({:data ({:clientId 870, :Id 1} {:clientId 555, :Id 3})} ? can anyone help please?

tws14:08:39

(apply merge-with into coll)

2
popeye15:08:11

that worked!!! but I did not get the function, Can you explain please

Tomas Brejla07:08:56

Nice use of apply :thumbsup:. Somehow I still keep preferring reduce in similar situations. It feels more natural (descriptive) to me : we're trying to reduce multiple maps by merging them to one map. Using reduce + with partial and concat even seems to be a little bit faster.

(c/bench (reduce (partial merge-with concat) input))
;; Evaluation count : 80769360 in 60 samples of 1346156 calls.
;;              Execution time mean : 789.774423 ns
;;     Execution time std-deviation : 29.622499 ns
(c/bench (reduce (partial merge-with into) input))
;; Evaluation count : 65356680 in 60 samples of 1089278 calls.
;;              Execution time mean : 918.308892 ns
;;     Execution time std-deviation : 34.212433 ns
(c/bench (apply merge-with into input))
;; Evaluation count : 67918800 in 60 samples of 1131980 calls.
;;              Execution time mean : 888.030305 ns
;;     Execution time std-deviation : 25.039100 ns

Cora (she/her)14:08:58

(mapcat :data my-seq) I think?

Cora (she/her)14:08:36

and then wrap that in a hashmap with a key of data

Cora (she/her)14:08:08

basically you'd want to use map to get each value for key :data, then you want to concat those sequences together, then put them back into a hashmap with the key :data

popeye16:08:16

(apply merge-with into coll) worked for me

Cora (she/her)16:08:34

I have no idea what that would do but if it makes sense to you

Cora (she/her)16:08:08

ok, looked up merge-with, makes sense here

Cora (she/her)16:08:58

I think you could use concat instead of into?

Cora (she/her)16:08:03

(apply merge-with concat [{:data [:foo :bar]} {:data [:baz :qux]}])
{:data (:foo :bar :baz :qux)}

Cora (she/her)16:08:05

but that depends on if you want it eagerly or lazily concatenated

bnstvn16:08:11

Are there any real performance difference between inline and external protocol implementations? How to choose which one to use if you can change the type? From “Clojure Programming” I understood that the main benefit of inline implementation is the performance, and probably should use `extend*`  — while I mostly see `defrecord`/ `deftype`  (I guess)

bnstvn16:08:27

Not sure i did the right thing on measuring performance, but :

(defprotocol Noop
  (dont-do [this]))

(defrecord InlineNoop []
  Noop
  (dont-do [_] nil))

(def inline-op (->InlineNoop))

(criterium.core/quick-bench
  (dont-do inline-op)) ;; ==> Execution time mean : 2.100368 ns

(extend-type String
  Noop
  (dont-do [_] nil))

(criterium.core/quick-bench
  (dont-do "asd")) ;; ==> Execution time mean : 2.118537 ns

bnstvn16:08:47

> Thus, inline implementations, while tempting because they appear so familiar (methods > in classes!), are more static than other protocol extension mechanisms, and are best > kept as an optimizing step. (Clojure Programming)

pithyless22:08:01

My understanding (reader beware): when extending protocol inside a defrecord, the generated class will implement the protocol's Java interface and later the protocol function will dispatch via the JVM type dispatch. Extending via extend-* will not implement that Java interface and the protocol function will dispatch via the protocol's dispatch table (which is theoretically slower by some factor, but it may not be perceptible outside of a tight-loop or some microbenchmark). The JVM can (at least theoretically) do a lot more optimization with an interface type dispatch, but whether this noticeable in your use-case is a separate story. :) This difference in implementation is an interesting leaky abstraction for another reason (aside from performance considerations). If you extend two protocols with the same function name, this is not possible via defrecord as it cannot implement the Java interface (2+ implementations for the same function name). But it will work just fine via extend-* since the functions are namespaced (and in this case no Java interface is implemented). Additionally, it's different in ClojureScript - where both syntaxes work, because CLJS defrecord allows implementing two different protocols with the same name and signature.

👍 3
Colin P. Hill23:08:11

Just a quick question on learning resources. 5 years ago or so I learned Clojure with "Clojure for the Brave and True". I finally landed a Clojure job, so now I have to shake off the rust and re-learn it. What's the best place to learn modern Clojure? Should I just re-read that same book, or are there more recent resources I should turn to?

jumar01:08:38

Programming Clojure is great and Joy of Clojure is still fantastic if you have more time to invest Also Clojure Applied perhaps minus the emphasis on records

tvirolai06:08:08

Web Development with Clojure (3rd edition, currently in "beta": https://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/) is a great practical resource. Clojure: the Essential Reference by Renzo Borgatti (https://www.manning.com/books/clojure-the-essential-reference) is the resource for going deeeeep