Fork me on GitHub
#beginners
<
2017-10-07
>
drewverlee00:10:06

is there a way to always get the latest?

drewverlee00:10:10

of a clojar?

drewverlee01:10:17

Also does anyone have their lein.profile available as an example. I’m curious what tools people use across projects

lovuikeng01:10:06

Use "LATEST" to replace the version number, then do a lein clean before re-compiling `:profiles {:dev {:dependencies [[re-frisk "LATEST"]]...`

lovuikeng01:10:13

try lein template to see how profiles are done... https://github.com/Day8/re-frame-template

drewverlee01:10:42

thanks much apperciated!

tdantas15:10:39

hey guys, I was reading the squeedo tests and one thing I didn’t get

(with-redefs [sqs/dequeue (fn [& _] [(<!! test-chan)])]
        (let [listener (#'sqs-server/create-queue-listener nil 1 2 1)
              message-channel (first listener)
              buf (second listener)
              wait-and-check (fn [count] ......
why are we using the #' on (#'sqs-server/create-queue-listener nil 1 2 1) ?

tdantas15:10:58

why not use sqs-server/create-queue-listener directly

dpsutton15:10:46

because it is private and not exposed in this manner: (defn- create-queue-listener.

tdantas15:10:17

thanks @dpsutton, what is the name of #'

dpsutton15:10:49

here's some info on it

dpsutton15:10:49

and some more info about other reader symbols at https://clojure.org/reference/reader#_dispatch

tdantas15:10:11

lovely ! thx

dpsutton15:10:24

my pleasure!

tdantas15:10:16

symbol -> Var -> value it is an indirection, right

dpsutton15:10:15

yes. i can't give you more details than a handwavy explanation though.

asiegf15:10:59

Hi! Does anyone know a simple example of eval with loader for providing predefined functions in clojurescript? I’m not quite sure to understand how it works from the documentation https://cljs.github.io/api/cljs.js/eval. The only implementation I could find is from https://github.com/ctford/klangmeister/blob/master/src/klangmeister/compile/eval.cljs, but it is still a bit too cryptic for me.

noisesmith16:10:04

@oliv the general idea is that a var is owned by a namespace and used to store the value of a thing in that namespace, if something is private you can't use it just by the symbol, but there's a workaround to access it via the var. The extra bit here is that if a var is called as if it were a function, clojure automatically looks up the current value in the var and calls that for you. The other place you see this pattern is if you are passing a function argument to a long running process (like an http server) and you want changes of the definition in the namespace to be reflected in the function called by the handler.

chris_johnson18:10:51

I’m confused about how to “use” promesa to get values in cljs - I can do something like (p/then (some-promise-returning-fn an-arg) #(cljs.pprint/pprint %)) and see the resolved value, but (p/then (some-promise-returning-fn an-arg) #(identity %)) (or any of several other things I’ve thought of to return the value I can interact with and see via pprint out to the calling level) returns simply #<Promise[~]>

chris_johnson18:10:32

so the promise is being resolved in my fn, but how do I get that resolved value out of the promise chain so I can, say, push it into a Reagent model?

noisesmith18:10:25

deliver it to something in your ratom?

tbaldridge18:10:46

I'd probably recommend using something like core.async instead @chris_johnson promises are the "one night stand" of async operations 😉

noisesmith18:10:56

the promise isn't the thing it delivers, it's a thing that eventually manages a callback - and you can use your handle to it to chain another callback or whatever

noisesmith18:10:10

and yeah, core.async is a smart choice too

tbaldridge18:10:21

But in general, in CLJS since you only have one thread you have to constantly chain callbacks or blocks of code until you deliver the result where it needs to go

chris_johnson18:10:25

I might do that, move from httpurr to cljs.http

chris_johnson19:10:17

Right, I get that part, what is surprising me (and therefore revealing to me a layer of context or knowledge I thought I had but don’t) is that I can “deliver” the value in the promise to pprint but apparently not to e.g. :body

noisesmith19:10:51

you can - but that's something with no side effect so there's no point

tbaldridge19:10:52

Right, because the code in the p/then hasn't run yet, so it has to return a promise

noisesmith19:10:54

you can't get the value out

noisesmith19:10:29

now if we had call/cc ...

tbaldridge19:10:47

(or delimited continuations)

noisesmith19:10:58

right - core.async is good enough here though

tbaldridge19:10:24

But this is the reason why ClojureScript doesn't have promises in the first place. @(promise ...some code...) can't work in JS

chris_johnson19:10:47

okay, and I definitely don’t want to do this in a side-effecting way because my eventual plan is to gather the results of several calls and put them all into a ratom (where “several” is large enough that trying to use promesa.core/all would be an affront to style and reason both)

tbaldridge19:10:12

That's async code...

tbaldridge19:10:24

It's all side-effecting

chris_johnson19:10:22

right, but what I’m saying is that I could in theory have this current chain “bottom out” at a side-effecting call to say, deliver a value into a ratom

chris_johnson19:10:39

I’m going to do a lot of these because of the way the API I’m calling out to is structured

tbaldridge19:10:50

That's what you'll have to do, there really isn't any other way in JS

noisesmith19:10:58

then use swap! to conj each onto a vector in an ratom?

tbaldridge19:10:03

One thing to consider is a message bus, and an event-sourcing model. At least in that way you have more insight into what the system is doing.

tbaldridge19:10:28

So you get something like (p/then (http-call url) #(send-message :http-received %))

tbaldridge19:10:09

But in JS you're stuck with side effects everywhere, and really the only way to deal with it is via message passing

chris_johnson19:10:57

that would make sense for a later version of this for sure (the event sourcing model)

tbaldridge19:10:53

heh, for that matter, even reagent uses message passing. A change to a ratom's data simply enqueues the ratom for later rendering. So any changes to the code in the ratom produce a side-effect

chris_johnson19:10:33

as an aside, what a remarkable demonstration of this community’s awesomeness that I drop a question at this level into #beginners on a Saturday afternoon and get responses from the two of you! 😄

chris_johnson19:10:20

If you see me at the conj, hit me up for a beverage of your choice (assuming your choice doesn’t run to pre-odium cognacs or anything else that requires a credit check before the barkeep gets it out from the cellar)

chris_johnson19:10:55

I do understand what I’m trying to do here, I was just surprised I guess that “directly return this part of the value” didn’t “count” as an effect in the same way that “pass this whole thing to pprint” did, if that even makes sense

noisesmith19:10:53

that's why I bring up call/cc - you can't return from the future into the past

chris_johnson19:10:39

I do have a p/resolved call in there, and I was hoping that p/then would be able to block on that and return the value directly but the use case I have for that is really just to verify the shape of the returned data at the REPL, I could certainly send the value off to a ratom without blocking, and pprint lets me see what I need to

noisesmith19:10:31

yeah 'blocking' is a no go period - you only have one thread

chris_johnson19:10:58

my years of Java/Clojure and weeks of Javascript/CLJS may be “helping” me build a conceptual model, here

Lucas Barbosa19:10:17

I am reading about refs and concurrency in Clojure, and this question popped into my head: If I have two refs, say a and b, and their values are restricted by some rule, say “a must be always greater than b”, is it possible to do a “ghost read” and get invalid data?

Lucas Barbosa19:10:58

An example: a has the value 1 and b has the value 0. Is it possible to deref a and get the 1, and before I read b, some transaction changes both of them to 10 and 5, and then i get 5 for b (which is wrong)?

noisesmith19:10:25

@lvbarbosa if you always use a function that respects that relationship, and always access both in the transaction, you can preserve that relationship

noisesmith19:10:18

but it would be simpler to put both as values in one atom (eg vector or hash-map) and preserve the relationship via the function passed to swap! or via add-watch to post-process and correct

Lucas Barbosa19:10:01

So I guess the “value tracking” of refs inside transactions only start at the first time I read that ref, right?

noisesmith19:10:36

if you use ensure it is valid for the whole transaction

Lucas Barbosa19:10:44

If I read ref a inside this transaction X, will the value of a be preserved until the end? Even if some other transaction change it

noisesmith19:10:52

that is what ensure is for

Lucas Barbosa19:10:57

oh, didn’t know about that

Lucas Barbosa19:10:06

I guess I’ll read about it later on the chapter

noisesmith19:10:14

some books might not mention it

noisesmith19:10:42

just remember you can't put side effects in the transaction (you need to know it's safe to bail on the transaction at any point and restart with new values)

Lucas Barbosa19:10:15

so the answer to my original question is: yes, it is possible to do ghost reads on unrelated refs

noisesmith19:10:30

right, but if you are careful you can prevent it, with ensure

Lucas Barbosa19:10:47

It makes sense that Clojure doesn’t handles that, because it would have to either A: capture the whole state of the program for that transaction or B: look ahead on the code to see what refs would be mentioned

Lucas Barbosa19:10:09

seems easier to just control that manually

noisesmith19:10:21

yup - that's the simple and flexible option

tbaldridge19:10:57

@lvbarbosa that's the difference between ensure, commute and alter. Ensure is a guard, commute says "update this value, I don't care about the old value", and alter is a ensure + commute.

Lucas Barbosa19:10:52

@tbaldridge I wish that was the first sentence I ever read about refs

tbaldridge19:10:15

For example, if you have a counter, (commute ref inc) will work as you're just incrementing a counter and don't really care if it changes in the middle of the transaction (normally), but a read/compute/update would require alter.

tbaldridge19:10:14

(^^ me really confused about 6 years ago)

chris_johnson20:10:15

huh - so I originally had this project set up to use cljs.http and core.async but moved to httpurr as an experiment because I thought I was having some issue with CORS and cljs.http

chris_johnson20:10:31

Later I found that my Pedestal CORS setup was jacked up, and I fixed it

chris_johnson20:10:10

now, I’ve gone back to cljs.http and I see the same {:status 0, :success false, ...} response coming out of cljs.http GET calls, even though a) I know that my CORS setup is good now because I’ve seen it work in httpurr and b) if I point at a local server I can see the pedestal.cors interceptor accepting the request and sending all the right headers (or building all the right headers)

chris_johnson20:10:20

I don’t suppose anyone has …seen that before

chris_johnson20:10:00

ha-ha! I learned two things: 1) when in doubt, revisit the browser JS console and 2) you need to set :with-credentials? false if you want cljs-http to do CORS correctly against a server that’s not setting Access-Control-Allow-Credentials

Lucas Barbosa20:10:49

@noisesmith @tbaldridge I guess I still need to clarify something about refs and atomic reads

Lucas Barbosa20:10:57

Is there any way, besides putting every related state together on a single reference type, to atomically deref more than one reference type?

noisesmith20:10:36

that's why transactions exist, if you ensure more than one ref in a transaction, the usage will be synchronized

noisesmith20:10:44

the transaction restarts if any of them change

noisesmith20:10:24

if by reference type you also mean vars, atoms, agents - that's a different story

Lucas Barbosa20:10:48

but if I do: (ensure a) (ensure b), wouldn’t I be vulnerable to a very unlucky timing where some other transaction updates b between those two statements?

noisesmith20:10:13

no because the whole transaction is restarted if either a or b is changed between start and finish

Lucas Barbosa20:10:12

So if either one of them changes even before I ensure, but after the transaction has started, I am guarded against external changes?

noisesmith20:10:48

that's what it's for as I understand it, yes

Lucas Barbosa20:10:55

this is beautiful

noisesmith20:10:06

everything that is ensured in the transaction becomes a restart condition if changed while the transaction is in effect

Lucas Barbosa20:10:49

Awesome, I am amazed

noisesmith20:10:31

@lvbarbosa but think about what it would mean if that was possible - to get that skew

noisesmith20:10:48

that means some other code is changing one of them but not the other in a way that lets them go out of sync

noisesmith21:10:09

because if not, you'd restart because one of them changed before the transaction ended but after you read it, right?

noisesmith21:10:43

and really the only protection you have for the relationship between the two is that you are careful that all your code preserves that relationship - you wouldn't even need a race condition to have that problem otherwise

Lucas Barbosa21:10:38

I created a toy example to check

Lucas Barbosa21:10:46

And it works exactly as you explained

Lucas Barbosa21:10:58

How do I paste a block of code here? Just command+v?

Lucas Barbosa21:10:06

To get it highlighted/formatted

Lucas Barbosa21:10:36

`(def a (ref 10)) (def b (ref 5)) (def resA (future (dosync (let [x @a] (Thread/sleep 3000) (println “Awake...“) (let [y @b] (println “Summing...“) (ensure a) (ensure b) (+ x y)))))) (def resB (future (dosync (Thread/sleep 1000) (println “Incrementing...“) (alter a inc))))

Lucas Barbosa21:10:48

well.. sorry for that

noisesmith21:10:16

putting '```' on each end should have done it

Lucas Barbosa21:10:34

The output was:

Incrementing...
Awake...
Summing...
Awake...
Summing...

Lucas Barbosa21:10:09

so resA‘s transaction was retried

Lucas Barbosa22:10:58

I’m loving these STM mechanisms to ensure consistency

Lucas Barbosa22:10:23

oh, but the deref will not trigger retries if the change is made after the derefing

Lucas Barbosa22:10:30

and that’s when ensure comes to play

Aron22:10:16

are there responses to this? http://z.caudate.me/on-whose-authority/ basically the same things kept me away from clojure (and java :D), so it would be great to see what others who understand the situation (unlike me) think of this?

noisesmith22:10:33

rich responded in the reddit post

noisesmith22:10:56

also that's probably better for #off-topic

Aron22:10:37

yeah, i am sure you know better

Aron23:10:19

that post from rich is disheartening, misses the point at least as much as the original "diatribe"

tbaldridge23:10:09

My thoughts...I'm tired. Tired of coming on reddit/slack, pouring hours of my personal time into helping people, and then some post that starts with "fuck Clojure" gets 200+ comments.

tbaldridge23:10:33

The Clojure community is one of the best I've been a part of in my years of programming, it's not without faults, but it's posts like that that make me say "what more do people want"?

tbaldridge23:10:23

Now, I know that post and those that agree with it are in the minority, it just sucks that that minority is so loud. And that it keeps coming up every 6 months.

manas_marthi10:10:59

Good observation!!. May be that minority is so loud because they start with hello-worlds and do a bit of CRUD and curse, while the majority is quietly building something useful or focusing on honing the skills. I consider myself part of the advanced-beginners group of Dryfus model of skill acquisition. We need a lot of advanced beginners to talk more. We can relate better to the new beginners than the experts.

tbaldridge23:10:47

(also several of the facts in the blog post are just false), but anyways, that's my take @ashnur 🙂

Michael Stokley23:10:17

hello! does clojure have "quasiquoting" like common lisp?

Michael Stokley23:10:07

from what i can tell it's ` paired with ~

Michael Stokley23:10:24

instead of ' paired with ,

noisesmith23:10:40

yes, the difference is that ` namespace qualifies things also

tbaldridge23:10:47

@michael740 that's pretty much it, also [email protected] slices a list into an outer list

tbaldridge23:10:07

`[1 [email protected][2 3] 4] -> [1 2 3 4]

Michael Stokley23:10:16

i did notice the namespace qualifying - but didn't know the term... is there a way to suppress that?

tbaldridge23:10:00

Not really, since it's super easy to shoot yourself in the foot, but you can hack it via `[~'foo] -> '[foo]

noisesmith23:10:41

if you need to suppress it, what you are doing is probably a bad idea, it's there to prevent some bugs that are very hard to deal with in practice (name capture issues)

noisesmith23:10:13

(not to say ~' is never called for)

noisesmith23:10:08

if what you are trying to emit is a let block (or any other local binding), use foo# which creates a non-qualified gensym that is safe to use

Michael Stokley23:10:15

fair enough. i'm a total beginner, working through "land of lisp", but in clojure. so i'm trying to translate common lisp into clojure. there's an example that uses all... unbound (?) symbols instead of strings and a sort of ... symbol interpolation or symbol formatting

Michael Stokley23:10:13

and they accomplish what i'm calling symbol interpolation with quoting and quasiquoting

noisesmith23:10:31

yeah, a lot of things in land of lisp are not what we would consider best coding practices

noisesmith23:10:12

also, you can do everything you need with str / symbol / list, ` is a convenience not a primitive language feature

Michael Stokley23:10:39

can you give an example?

noisesmith23:10:36

+user=> (defmacro foo [& body] (list* 'clojure.core/+ body))
#'user/foo
+user=> (foo 1 2)
3
+user=> (macroexpand-1 '(foo 1 2))
(clojure.core/+ 1 2)

noisesmith23:10:24

not that I recommend writing real macros that way - but you shouldn't be doing logic via string splicing in macros either, so shrug

Michael Stokley23:10:13

thank you for your help, @noisesmith 🙂