Fork me on GitHub
#beginners
<
2021-02-21
>
Adrian Imanuel04:02:12

hi, can someone explain how this re-gex pattern ways of working work? I tried to

(count (re-seq #"1" "1234554321112345678")) 

;;=> 4 
but if i do this, i got an error
(count (re-seq #(str 1) "1234554321112345678")) 

;;=> Execution error (ClassCastException) at user/eval2152 (REPL:238).
class user$eval2152$fn__2153 cannot be cast to class java.util.regex.Pattern (user$eval2152$fn__2153 is in unnamed module of loader clojure.lang.DynamicClassLoader @32d7ce6f; java.util.regex.Pattern is in module java.base of loader 'bootstrap')
I tried to make function where the 1 as parameter.

dpsutton04:02:17

re-seq can't take a function in the first position. it must be a regex. and you probably meant #(str %). What you wrote, #(str 1) is a function of zero arguments which will return "1"

Adrian Imanuel04:02:07

@dpsutton yes, i meant #(str %) but it still gives an error

Adrian Imanuel04:02:48

(defn asdf
  [x]
  (count (re-seq #(str x) "1234554321112345678")))

Adrian Imanuel04:02:58

i think i found the answer

(count (re-seq  (re-pattern (str 1)) "1234554321112345678"))

dpsutton04:02:51

(re-pattern (str 1)) is just (re-pattern "1") which is basically just #"1". you just can't use a function there just the same as you can't add two to a function (+ 1 (fn [] 3))

Adrian Imanuel05:02:25

oh, sorry to be clear, i want to make the number 1 become parameter of a function. sorry for bad english, here's my full code

(defn asdf
  [x]
  (count (re-seq  (re-pattern (str x)) "1234554321112345678"))
*revised

dpsutton05:02:59

(count (re-seq (re-patter x) ...)

Adrian Imanuel05:02:22

i found that some programmer use ->> macro like this below, is this some preferences or something? does it has an impact to the program? because i still can't do this yet, i only use simple parentheses.

(defn nb-dig [n d]
  ((->> (range (inc n))
        (mapcat #(str (* % %)))
        frequencies)
   (first (str d))))

dpsutton05:02:55

the extra parens there causes me to do a double take. i'd use a let binding or a (get (->> ...) (first (str d))) to make it a bit more clear what's going on there

devn06:02:18

@adrianimanuel there’s no impact to the program, it’s just a style choice.

devn06:02:13

People use it to write something that reads like A.b.c.d instead of (d (c (b A)))

devn06:02:11

If you want to see the equivalent expression you can do (macroexpand ‘(->> (range 10) (filter even?)))

Adrian Imanuel06:02:16

@devn thank you for the explanation, i got used to (d (c (b A))) since i used ms. excel extensively lol

devn07:02:54

Excel is a fit predator!

3
Ilmari Pohjola10:02:20

Hi! I have a very easy noob question, that I do not find answer by googling. I've got to lists (:x :y :z) and (\x \y \z). I simply want to construct a map {:x \x :y \y :z \z}. Only thing I found was interleave, which unfortunately does not return a map. Any suggestions?

bhaim12312:02:57

Hi, When should I use Java Thread and not Future? (or maybe I should ask, does it matter?) I know that in Future I can wait for the thread to finish and see the return status, and for Java Thread I can’t, right?

emilaasa13:02:13

What are you trying to do?

Adrian Imanuel13:02:52

future : You can use futures to run tasks on a separate thread and then forget about them, but often you’ll want to use the result of the task. The `future` function returns a reference value that you can use to request the result. based on https://www.braveclojure.com/concurrency/ as for javathread, i didn't know bout that yet.

bhaim12313:02:46

@U6T7M9DBR Mainly trying to understand the difference 🙂

Alex Miller (Clojure team)14:02:57

Futures run a function on a thread

Alex Miller (Clojure team)14:02:09

So they are not that much different

Alex Miller (Clojure team)14:02:00

Futures use a cached thread pool though so it can be more efficient if you’re doing this a lot (will reuse the same thread if possible)

bhaim12314:02:18

Thanks @U064X3EF3, Will Future run as a Java thread at the end? and the difference is only that Clojure allows to cache the result while in Thread we can’t access it?

Alex Miller (Clojure team)14:02:27

Futures also have a useful feature - binding conveyance. The future function runs in an environment where any dynamic bindings are set like they were where you created the future

Alex Miller (Clojure team)14:02:33

Yes, futures run on a Thread (all Clojure functions implement Runnable so can be passed directly to a thread)

bhaim12314:02:13

Thanks, so what is this cached thread pool though that they run on?

Alex Miller (Clojure team)14:02:30

It’s one of two in the Clojure runtime

Alex Miller (Clojure team)14:02:31

The other is for compute only tasks and is a fixed size pool

Alex Miller (Clojure team)14:02:00

And FYI I wrote a whole chapter about concurrency in Clojure in Clojure Applied with more detail

emilaasa15:02:58

In my mind a Future is a higher level concept than a Thread as well.

emilaasa15:02:07

As in the Future represents the result of an operation, whereas a Thread might be the actual lower level construct that could get you that result.

andy.fingerhut17:02:23

You can interact with a thread while it runs in semi-arbitrary ways while it runs, I believe. One of the things about a future is you are effectively saying "I don't care to interact with you at all, except for you to tell me when you are done, and what result you got"

andy.fingerhut17:02:49

You could start a thread and pass messages / intermediate results back and forth N times, or indefinitely.

andy.fingerhut18:02:32

I could be off on this -- but I suspect at least most futures are created in a context that have the "limited interaction" I mention above.

bhaim12318:02:00

Thanks everyone! I think it is time for to go and read @U064X3EF3 chapter 🙂

Alex Miller (Clojure team)19:02:59

well I disagree that a future may only care about the result (but that is the primary use case). I've certainly used futures to background an operation that interacted with the original thread more than once via promises.

bhaim12305:02:16

@U064X3EF3 the chapter in Clojure Applied is Futures and Promises*?*

Alex Miller (Clojure team)05:02:45

I don't think that's what it's called, but it's chapter 5

bhaim12306:02:16

Many thanks 🙂

bhaim12308:02:19

@U064X3EF3 just to make sure I got it right: The Future is actually using a Java thread pool that Clojure is holding behind the scene? This pool is also used to run the go blocks. The pool default size is the num of processors, but if needed it will be larger?

Alex Miller (Clojure team)14:02:49

Yes, Clojure future will run on a Java thread pool in the Clojure runtime Different pool (maintained by core.async) is used to run go blocks The future thread pool can expand without limits but caches unused threads for a while and will reuse if possible

bhaim12318:02:36

Thank you very much @U064X3EF3! Now I’ll try to go and understand the core.async thread pool 🙂 any reading material you recommend ?

Alex Miller (Clojure team)19:02:38

I mean, it's just a thread pool, not really anything specific to read about that

bhaim12319:02:17

🙂 Thanks

evocatus16:02:38

hi! getting familiar with clojure.spec. It's great so far. I have a question though

evocatus16:02:56

How can I write a spec to check if a number is a valid uint64?

evocatus16:02:16

considering it was fetched from a database column with this type

evocatus16:02:49

looks like Java doesn't support unsigned types (which is a big surprise for me)

evocatus16:02:04

maybe I should just use nat-int?

seancorfield17:02:40

@gr.evocatus If it was fetched from the database as a uint64, you may find that is it a BigInt or BitInteger rather than a Long (if it is the latter, it's not going to correctly hold any value larger than Long/MAX_VALUE) -- in which case it won't satisfy nat-int? (because 1234N -- a Clojure BigInt -- does not satisfy int?, but does satisfy integer?).

dev=> (for [pred [int? integer? nat-int? pos-int? neg-int?]
 #_=>       v    [-100N -100 0 100 100N]]
 #_=>   [v (pred v)])
([-100N false] [-100 true] [0 true] [100 true] [100N false] ; int?
 [-100N true] [-100 true] [0 true] [100 true] [100N true] ; integer?
 [-100N false] [-100 false] [0 true] [100 true] [100N false] ; nat-int?
 [-100N false] [-100 false] [0 false] [100 true] [100N false] ; pos-int?
 [-100N false] [-100 true] [0 false] [100 false] [100N false]) ; neg-int?

grazfather19:02:34

what does clojure-lsp offer over everything in Cider?

dpsutton19:02:54

clojure-lsp offers high quality static analysis that does not depend on a running instance of your code. this means that it can do quite a bit without running things, but it can miss things that are only apparent with an actual running instance: macros which expand to forms, run time requiring, loading of things, etc. CIDER runs in your project and can basically query all of this stuff from the repl, much like a clojure repl provides. (eg, ns-publics, doc, info, ...)

grazfather21:02:27

awesome thank you (and ty borkdude, too)

dpsutton21:02:27

just FYI he is the author of the fantastic static analysis tool

dpsutton19:02:54

they can be quite complementary. a standout from the analysis is the clojure-lsp will perform refactorings on your code, introduce lets, extract functions, rename things, etc. CIDER can accomplish this with an extra refactor-nrepl dep, but i don't believe its quite at the level of what clojure-lsp can do

borkdude19:02:04

yes, they are complimentary, I would not want to program without a REPL / CIDER, however in CLJS I hardly ever use a REPL because that's too much friction for me. I rely entirely on hot-reloading (figwheel) there or for node projects I just call require + :reload from a nodeJS REPL in my terminal. So clojure-lsp now provides navigation in CLJS whereas before I didn't have this at all for a long time

jumar04:02:46

I checked the beginning of your video and I'm wondering how well Cider plays with LSP. E.g. the autocomplete looks something that can potentially conflict if you use both things at the same time. How is that handled?

borkdude07:02:57

Ask in #lsp, I’m by no means an expert

borkdude19:02:49

one feature that I believe CIDER (and maybe even Cursive?) doesn't have is finding keyword references. I demonstrate this in a Youtube video I made yesterday, towards the end.

borkdude19:02:12

e.g. it can find references to :clojure.string/foo even if you write it as ::str/foo

evocatus20:02:00

can I write a spec to check some complex conditions like "values of map ::total are sums of values of the same keys of maps inside ::rows"?

robertfw20:02:09

@gr.evocatus You can write your own predicates, so you can write specs that check just about anything. I don't quite understand the data structure you are describing so can't go into more depth about how you might want to accomplish that

evocatus20:02:56

But how do I do it? Just something like this? (s/def ::reply (s/and (s/keys :req [::rows ::total]) #(some-complex-checks)))

robertfw20:02:19

yup. note that if you want to be able to generate values using (s/gen) you'll need to provide your own generator with s/with-gen

👍 3
ribelo20:02:10

Is it possible to make an extend-type for PersistentHasMap and PersistentArrayMap in one go?

ribelo20:02:29

it's basically the same thing

dpsutton20:02:20

(extend-protocol Foo
  clojure.lang.APersistentMap
  (f [_] :foo-on-map))
worked for me

dpsutton20:02:46

(f {}) and (f (into {} (map (fn [x] [x x])) (range 1000))) both return :foo-on-map

Alex Miller (Clojure team)21:02:24

You really should not be extending the Clojure concrete types like that - much better to make your protocol extensible via metadata

ribelo21:02:20

I heard something somewhere about metadata, so I'm going to go read more

Alex Miller (Clojure team)21:02:19

(defprotocol Foo :extend-via-metadata true (f [_]))
(defn decorate-map [m] (with-meta m {`f (fn [_] :foo-on-map)}))
(f {:a 1}) ;; error, no impl
(f (decorate-map {:a 1})) ;; :foo-on-map

Alex Miller (Clojure team)21:02:26

that's all there is to it

Alex Miller (Clojure team)21:02:00

types like APersistentMap, PersistentHashMap, PersistentArrayMap should be considered concrete implementation details inside of Clojure, not public APIs you can rely on, so you should really never be extending protocols to them. IPersistentMap is the proper generic interface, but even that I would be hesitant about as protocol extension on interfaces can open you up to diamond inheritance resolution issues

seancorfield21:02:39

@huxley One of the things that is really nice about extending protocols via metadata is that you can use anything that supports metadata, such as a Clojure function. In next.jdbc, it provides a function to support Stuart Sierra's Component library for creating database connection pools, and it uses a function (that returns the pool) with metadata to implement Component's stop function: https://github.com/seancorfield/next-jdbc/blob/develop/src/next/jdbc/connection.clj#L287-L318

ribelo21:02:07

I'm going to start reading