Fork me on GitHub
#beginners
<
2019-11-05
>
michael.e.loughlin09:11:04

is there a flow chart for deciding which concurrency primitives to use?

noisesmith18:11:49

if you aren't sure, the right answer is usually atom

noisesmith18:11:55

most people never need agent

noisesmith18:11:15

ref improves on atom when there's enough contention that it becomes a perf bottleneck that matters

noisesmith18:11:40

(eg. holding many values in one hash-map in an atom, vs. synchronized updates to a group of refs)

michael.e.loughlin22:11:44

Thanks! What's the appropriate way to wait for, say, a bunch of HTTP requests without blocking?

noisesmith22:11:10

usually the simplest thing for that is a future, which is an object that will eventually provide a result or error, and you can ask it if it's completed etc.

noisesmith22:11:22

it uses a thread pool under the hood

noisesmith22:11:50

(ins)user=> (doc future)
-------------------------
clojure.core/future
([& body])
Macro
  Takes a body of expressions and yields a future object that will
  invoke the body in another thread, and will cache the result and
  return it on all subsequent calls to deref/@. If the computation has
  not yet finished, calls to deref/@ will block, unless the variant of
  deref with timeout is used. See also - realized?.
nil
(ins)user=> (future (+ 1 1))
#object[clojure.core$future_call$reify__8439 0x235a0c16 {:status :ready, :val 2}]
(ins)user=> @*1
2
(ins)user=> (def err (future (/ 1 0)))
#'user/err
(ins)user=> @err
Execution error (ArithmeticException) at user/fn (REPL:1).
Divide by zero
(ins)user=> (future (Thread/sleep 20000))
#object[clojure.core$future_call$reify__8439 0x63fdab07 {:status :pending, :val nil}]
(ins)user=> ; deref / @ on above would not complete until 20 seconds after it was created

noisesmith22:11:11

notice how err doesn't actually bubble anything up until dereferenced

noisesmith22:11:14

(the *1 variable is just a convenience, it lets you refer to the last result in the repl)

m373h4n14:11:43

I was about to write someting like (contains? nil coll) if it was elixir I would write Enum.member? to check if list contains nil but in documentation I saw contains? for keys and there is no function like member?

noisesmith18:11:42

btw the syntax is (contains? coll nil) - for indexed / lookup collections only of course (sets, hash-maps)

m373h4n14:11:18

(defn phones [p-list]
  (->> p-list
       (mapv #(re-matches #"^\d+$" %))
       (WHAT TO WRITE HERE?)
       ))

(def correct ["2161234567" "5551234567" "8881234567"]) ;Expected TRUE
(def incorrect ["ABCDEFGHIJ" "55512a34567" "8881234567"]) 

dpsutton14:11:44

(some pred-fn coll)

dpsutton14:11:45

(some nil? coll) or the other contrapositive i guess, (every? some? coll) depending if you are looking for the presence of nils or the absence of nils

dpsutton14:11:12

the rationale is that contains? is always constant time and you need to do a linear scan. The functions guarantee (or try to) indicate their cost across any abstraction they operate on

m373h4n14:11:49

thank you every? some? worked as i expected 🙂

joshkh15:11:27

could someone please remind me how i might make the the following object seqable?

(first #datom[123456789123 1 "hello world" 987654321 true])
Don't know how to create ISeq from: datomic.client.impl.shared.datom.Datom
i remember using something like (defprotocol Datom ...) and then (->Datom #[...] ) but i can't get the syntax quite right.

bfabry16:11:31

I think you want extend and clojure.lang.ISeq as the interface

dpsutton16:11:12

however this doesn't look like a great thing to do. why do you want to be able to call first on a datom?

bfabry16:11:38

yeah imo it would be "surprising" to anyone reading it

dpsutton16:11:05

like if you saw (first #inst "2019-11-05") what would you expect to happen?

joshkh17:11:15

yes, i was hoping to use first and in the example above get back 123456789123, and also to destructure the object in a let: (let [[a b c d e f] datom]]).

joshkh17:11:06

> why? just for easier destructuring. i'm sure i did this a year ago in one little line of code.

dpsutton17:11:48

ah ok. that makes sense 🙂

joshkh17:11:23

that being said, i'm having trouble getting any value from the vector-looking object 😉

joshkh17:11:42

ah, nth worked

seancorfield17:11:27

Can you call keys on that datom? According to the docs, it looks like there's named key access to the fields in a datom...

seancorfield17:11:55

Hmm, some of the examples look like :v, :a, :e would works as keys... But there doesn't appear to be much documentation about accessing the elements of a datom directly.

seancorfield17:11:08

And I've found another part of the docs that seems pretty clear that it's "just" a tuple so that jives with nth working (and maybe vector destructuring which I thought only used nth?).

joshkh17:11:03

for educational purposes i'll admit that i just assumed destructuring wouldn't work after i saw that first failed.

joshkh17:11:13

thanks @ you're completely right

jaihindhreddy04:11:51

You can look at the source of clojure.core/destructure to see how that works. It is quite gnarly though.

jainsaurabh7820:11:46

Hi I am facing issue while installing clojure inside the docker..any pointers please. I am trying to install it with Java 11

seancorfield20:11:55

@jainsaurabh78 Maybe you can explain what commands you are trying to run and how they are failing?

jainsaurabh7821:11:22

I am working on tap-mssql for pipelinewise that is written in clojure language. To create an image of my pipelinewise doker I need to install clojure as well that requires leiningen (RUN curl https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein > lein && mv lein /usr/local/bin/lein && chmod a+x /usr/local/bin/lein). when it installs clojure it is giving this error java.io.IOException: Cannot run program "/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java" (in directory "/pipelinewise/.virtualenvs/tap-mssql"): error=2, No such file or directory at java.lang.ProcessBuilder.start (ProcessBuilder.java:1128) java.lang.ProcessBuilder.start (ProcessBuilder.java:1071) java.lang.Runtime.exec (Runtime.java:591) jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (NativeMethodAccessorImpl.java:-2) jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) java.lang.reflect.Method.invoke (Method.java:566) clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:167) clojure.lang.Reflector.invokeInstanceMethod (Reflector.java:102) leiningen.core.eval$sh.invokeStatic (eval.clj:179) leiningen.core.eval$sh.doInvoke (eval.clj:173) clojure.lang.RestFn.applyTo (RestFn.java:137)

jainsaurabh7821:11:09

I have version JAVA 11 installed but is it checking for 8..

noisesmith21:11:37

lein itself is a single shell script, the place where it is looking for 8 shouldn't be hard to find

noisesmith21:11:29

just doing a quick search in that script myself, it looks like if you export JAVA_CMD to point to your java executable it should use that

noisesmith21:11:44

it could be something incorrect from the parent env is leaking into the docker context

jainsaurabh7821:11:34

ok. checking for JAVA_CMD

noisesmith21:11:37

regardless of why it's set wrong, you can probably fix your current issue by setting the right value when running lein

noisesmith21:11:18

there's also LEIN_JAVA_COMMAND which is less likely to be set accidentally, and takes precedence if both are set

jainsaurabh7822:11:40

Any suggestion how to set Lein_java_command and java_command

jainsaurabh7822:11:12

I tried setting up /usr/lib/jvm/java-11-openjdk-amd64 in JAVA_HOME variable but still it is looking for 8

noisesmith22:11:21

these are environment variables, the easiest way is to use export or set them directley eg. JAVA_CMD=/path/to/java lein

noisesmith22:11:31

it's not even looking for JAVA_HOME