clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
Clypto 2020-09-24T04:29:21.006Z

what's up with clj-kondo in vscode, it seems like it can't see dependencies and fill up files with unresolved symbols in the editor

practicalli-john 2020-09-24T18:52:52.062900Z

I hope you are using the Calva extension for VSCode, there is another Clojure extension that is not as capable Recomend using https://marketplace.visualstudio.com/items?itemName=betterthantomorrow.calva

Clypto 2020-09-26T16:26:42.187700Z

yes, I am

practicalli-john 2020-09-26T17:51:50.188700Z

hopefully the nice people on #calva can help you if you are still having issues.

seancorfield 2020-09-24T04:41:33.006900Z

@clypto Probably a better question for #clj-kondo and/or #vscode / #calva ?

seancorfield 2020-09-24T04:42:01.007500Z

(although it sounds like you haven't run the project initialization for clj-kondo per the README?)

Clypto 2020-09-24T04:43:03.007800Z

maybe, but I'm not sure where said readme is

seancorfield 2020-09-24T04:43:22.008200Z

Er, the clj-kondo readme?

seancorfield 2020-09-24T04:43:53.008400Z

https://github.com/borkdude/clj-kondo#project-setup

Clypto 2020-09-24T04:45:44.008900Z

ah, I was looking at the VS Code extension page

Clypto 2020-09-24T04:45:46.009100Z

which is quite sparse

Clypto 2020-09-24T04:47:24.009500Z

I think I had grand ideas on what the extension automatically did šŸ˜„

seancorfield 2020-09-24T05:03:21.010700Z

Yeah, I had to blow away the .clj-kondo/.cache folder in one of my projects today and re-run the parallel lint initialization thing again because it got stuck thinking a couple of functions had different arities after some refactoring...

vlaaad 2020-09-24T05:10:53.010800Z

Of course, but I don't want to have it lying around for more time than built jars are lying around

vlaaad 2020-09-24T06:26:41.000100Z

...because for the build tooling, pom.xml is a mutable place that different tools write to or read from

borkdude 2020-09-24T06:38:59.002200Z

If you refactor using the same editor that should not happen, since it lints files when editing and the last refactored file has the last known valid arities

nickt 2020-09-24T12:34:50.004600Z

Hey folks, I'm struggling a bit with variadic functions this morning– I have a function defined like:

(defn create-node [node-type props & children]
  ...blah)
And then I have a call site where I write (create-node "x" {}), and when I run the cljs compiler I get "wrong number of arguments passed to create-node"

nickt 2020-09-24T12:35:06.005Z

Why is that the wrong number of arguments? I want that call to be valid and for children, in that case, to be an empty list

2020-09-24T12:48:00.007800Z

I don’t remember the answer to your question about arity, but the ā€œcreate-nodeā€ name reminds me of a bug I ran into where I used a variadic argument to pass in some child nodes, and it blew up as soon as I tried to create a node with a large number of children. There’s a limit on the number of arguments a Java method can accept, so just a caveat in passing.

nickt 2020-09-24T12:48:24.008100Z

ok, thanks, that's definitely helpful

nickt 2020-09-24T12:48:52.008700Z

I just tried taking the list of children manually instead of via a variadic parameter, and I'm hitting the same "wrong number of argugments" still

nickt 2020-09-24T12:49:08.009100Z

create-node can call itself recursively... would that have anything to do with it?

2020-09-24T12:49:21.009400Z

Could be, depending on how it’s recursing

2020-09-24T12:49:50.010100Z

Your original defn looks correct to me, fwiw

2020-09-24T12:50:33.011800Z

What’s the exact text of the error? It should tell you how many args it was expecting vs how many it got.

nickt 2020-09-24T12:51:05.012700Z

WARNING: Wrong number of args (3) passed to cljs.core/create-node at line 12

Ed 2020-09-24T12:51:12.012900Z

It works for me ... Is create node recursive? Is there something in ...blah that's actually causing the error?

% clj --main cljs.main --repl
 ClojureScript 1.10.758
 cljs.user=> (defn create-node [node-type props & children] :blah)
 #'cljs.user/create-node
 cljs.user=> (create-node "x" {})
 :blah
 cljs.user=>

nickt 2020-09-24T12:51:24.013500Z

and this is my new fn def:

(defn create-node [node-type props children]

2020-09-24T12:51:48.014500Z

Ok, that’s sounding like your REPL has stale code stuck in it somehow, can you restart?

borkdude 2020-09-24T12:51:49.014600Z

@nickt It says cljs.core/create-node which seems wrong

2020-09-24T12:52:09.015400Z

oh, derp, yeah, I missed that, good catch

dpsutton 2020-09-24T12:52:24.015900Z

That means need to refer clojure exclude create-node

2020-09-24T12:52:48.016500Z

or name your function something different

nickt 2020-09-24T12:52:52.016700Z

ohhhh man, does clojure have its own create-node?

borkdude 2020-09-24T12:53:01.017Z

it seems cljs has

2020-09-24T12:53:02.017100Z

Apparently cljs at least does.

2020-09-24T12:53:05.017300Z

lol

2020-09-24T12:53:35.017800Z

Try (doc cljs.core/create-node)

nickt 2020-09-24T13:02:53.018Z

oh mannnn

nickt 2020-09-24T13:03:15.018400Z

wow, well thanks y'all. That would have taken me a long time to figure out šŸ™‚

nickt 2020-09-24T13:03:25.018600Z

(clojurescript newb)

nickt 2020-09-24T13:03:55.018900Z

so how would I refer exclude it?

nickt 2020-09-24T13:11:03.019900Z

also, side question, is there a good way to accept a variadic children or an explicit list of children?

nickt 2020-09-24T13:12:36.020700Z

it seems my best bet would be to make that definition be [node-type props & children] but then check if the first element in children is itself a list. If it is, use that as my children array?

alexmiller 2020-09-24T13:15:01.021600Z

I would recommend not doing that and just picking one or the other

alexmiller 2020-09-24T13:16:04.022400Z

It’s just easier to understand and maintain

nickt 2020-09-24T13:16:51.023200Z

@alexmiller thanks, definitely agree, but I would like to enable syntax like (create-node "x" 1 (create-node "y" 2))

nickt 2020-09-24T13:17:50.024Z

while also enabling syntax like (create-node "x" 1 (map (fn [child] (createNode...)) (range 10)) yknow what I mean?

nickt 2020-09-24T13:18:17.024800Z

Maybe there's some macro sugar I could use to enable this while preserving a singular notion of create-node's interface

alexmiller 2020-09-24T13:18:38.025800Z

I've only ever regretted doing this

āž• 4
šŸ˜„ 1
alexmiller 2020-09-24T13:19:00.026500Z

or make two fns

borkdude 2020-09-24T13:19:27.027500Z

@nickt In that case I would make create-node accept always a list of children. [(create-node ...)] is not much more typing than (create-node ...). or indeed create another fn

alexmiller 2020-09-24T13:19:38.027900Z

that's probably what I would do as well (list)

nickt 2020-09-24T13:20:23.028600Z

hmmm ok, yea, fair

borkdude 2020-09-24T13:20:49.029200Z

btw I think props like {"x" 1} is also better than passing those separately

nickt 2020-09-24T13:21:55.030100Z

why's that?

borkdude 2020-09-24T13:22:58.031600Z

you could have something like INode where you represent multiple children as a NodeSeq which implements INode so passing multiple or one is valid in terms of your model about passing props: easier parsing, passing, etc

borkdude 2020-09-24T13:24:30.032100Z

Take a look at hiccup, reagent, etc

nickt 2020-09-24T13:24:52.032300Z

iiinteresting

nickt 2020-09-24T13:25:43.032600Z

oh man, I should have just started here

nickt 2020-09-24T13:28:35.033500Z

hmm ok, lot for me to think about. Thanks @borkdude and @alexmiller

2020-09-24T14:05:18.037700Z

Is there a better way to use a different default printer than just starting a subrepl? for example if I want my repl to always use https://github.com/brandonbloom/fipp to print, I have the following evaluated when I start a repl:

...
(:require [clojure.main :as main]
          [fipp.edn :refer [pprint] :rename {pprint fipp}]
          [fipp.repl :refer [pst]])
...
(main/repl
    :caught pst
    :print fipp
    )
This works ok but then there are some times where it does cause subtle issues and it takes awhile to remember to try without fipp. Is this inevitable? I'm currently using inf-clojure on emacs.

vncz 2020-09-24T14:20:55.038600Z

Does anybody know any good way to parse nested query strings in Pedestal? It is currently able to automatically turn qs in maps (`?q=1&b=2` => {:q 1 :b 2} ), but I would need something a little bit more elaborate, such as ?foo[bar]=baz => { :foo {:bar "baz" } }

vlaaad 2020-09-24T14:24:45.039400Z

do you control the query params generated by client?

vncz 2020-09-24T14:25:27.039900Z

Yes I do @vlaaad; I can reshape it in case there's a format that Pedestal will deserialise automagically

vlaaad 2020-09-24T14:25:49.040300Z

IIRC query string is by definition is just a string

vlaaad 2020-09-24T14:26:09.041Z

e.g. k1=v1&k2=v2 is pure convention

vlaaad 2020-09-24T14:26:17.041500Z

just dump your edn there šŸ˜„

vncz 2020-09-24T14:26:25.041800Z

Ah, that ain't a bad idea after all

vncz 2020-09-24T14:26:40.042300Z

Does Pedestal auto evaluates EDN strings to be a real map?

vlaaad 2020-09-24T14:26:45.042600Z

that might be a dangerous idea šŸ™‚

vncz 2020-09-24T14:26:56.043100Z

Well yeah, if that calls functions and stuff

vncz 2020-09-24T14:27:08.043900Z

(I would be assuming Pedestal would be doing some sanitisation?)

vncz 2020-09-24T14:27:33.045Z

I would regularly use a body, but this is a GET call and I want to go through a query string

vlaaad 2020-09-24T14:27:34.045200Z

nono

vncz 2020-09-24T14:27:39.045500Z

…but I do need to pass a deep object

vlaaad 2020-09-24T14:27:42.045600Z

clojure.edn/read-string is safe

vncz 2020-09-24T14:27:56.045900Z

…and I do have a spec for my object

vlaaad 2020-09-24T14:28:11.046200Z

this is a dangerous idea if you’ll want to make this endpoint consumable by other clients as well

vlaaad 2020-09-24T14:28:28.046600Z

e.g. public

vncz 2020-09-24T14:28:40.046800Z

My HTTP endpoint should receive a ::children from the Query String (somehow)

2020-09-24T14:29:25.047100Z

not dangerous — perhaps annoying at best šŸ˜„

2020-09-24T14:29:35.047400Z

it’s just an encoding

2020-09-24T14:30:24.047600Z

idk, I guess I can see the argument for, ā€œEDN doesn’t have an encoder in every lang.ā€

vlaaad 2020-09-24T14:30:46.047800Z

that’s my argument, yes :)

vncz 2020-09-24T14:31:31.048Z

Well as long as there's a JSON to EDN converter I'd be ok I guess šŸ™‚

vncz 2020-09-24T15:01:06.050Z

Is there a way to declaratively set a spec check on a payload in Pedestal or shall I manually put this boilerplate every time? https://github.com/XVincentX/clojure-playground/blob/master/src/app/core.clj#L21-L23

vncz 2020-09-25T13:46:25.092700Z

Oh yeah you're right, assoc is replacing

2020-09-24T15:17:57.050500Z

I would write an interceptor to do that

vncz 2020-09-24T15:28:01.051Z

Ok thanks @codonnell — I was thinking about the same, just wondering if Pedestal had something out of the box

2020-09-24T15:29:41.051200Z

There is likely a library that provides such an interceptor, but I'm not sure how worthwhile it would be to bring in a dependency for that. Shouldn't be more than a few lines of code, and it's nice IMO to have full control over the behavior.

kennytilton 2020-09-24T16:32:37.051400Z

I generally agree with others clucking their tongues over this, but for geenrating children it is definitely mad useful to be able to supply an atom or list or even nested list and then Just Flatten(tm) the input. The one constraint of course is being sure we can live with flatten ! In my fav use case I am building children for a UI/Dom node and I know flatten will stop when it gets to a node, and also I knw the parent demands a flat list of child nodes. Now I can bung together whatever I want creating children and have it all flattened before hitting the parent. hth

kennytilton 2020-09-24T16:33:34.051600Z

I will check now on what clj flatten does. (I have my own from my CL days.)

vncz 2020-09-24T16:34:42.051800Z

Yes, makes sense. I'll see if I can come up with some code. Thanks!

kennytilton 2020-09-24T16:35:51.052Z

Ah, no, (flatten 42) => nil, we want 42.

kennytilton 2020-09-24T16:42:25.053300Z

Here’s my wrapper for any thing from an atom to a nested list of atoms. The *par* bit can be ignored. The doall is likewise sth specific to my usage. Note that the rest arg guarantees some list will be seen by the innards to avoid the flatten discard of atoms. Oh, and we gracefully handle some nested generator deciding not to create any nodes, a classic in reactive/dynamic UIs, and discard nils.

(defmacro the-kids [& tree]
  `(binding [*par* ~'me]
      (assert *par*)
      (doall (remove nil? (flatten (list ~@tree))))))

paul931224 2020-09-24T16:50:40.057500Z

Hello guys! I made a reservation system. The mechanism is: 1. read from mongo->decide if there is free space 2. if free, insert reservation, if not free, don't. This function is called add-reservation . My problem is, add-reservation is behind a server. I would need the to run only one add-reservation at a time, because there is a concurrency problem when multiple run at once. I use agent and send reservations to it. Is there a better way?

lukasz 2020-09-24T16:57:13.058200Z

Locks are commonly used for this kind of stuff, but that's beyond Clojure's scope

alexmiller 2020-09-24T17:00:22.059100Z

well, locks are fine if you need one. an agent is a good solution, assuming you have only one server

lukasz 2020-09-24T17:09:40.060200Z

Definitely, locks only make sense if you have more than one server. Maybe I misunderstood the question :thinking_face:

hmaurer 2020-09-24T17:12:21.061100Z

Hello! Quick question: what’s the term for an aggregate (e.g. a sum) that isn’t declaratively specified, but instead is updated imperatively on every event? e.g.

total_payroll = select sum(salary) from employee; 
v.s.
total_payroll = 0
on insert employee, total_payroll += salary
on delete employee, total_payroll -= salary
on update employee, total_payroll += (new_salary - previous_salary)
I know there is a term for it but I forgot what!

paul931224 2020-09-24T17:51:18.062200Z

I'll check the locks too! thanks!

2020-09-24T17:58:53.062300Z

running total? rolling sum?

practicalli-john 2020-09-24T18:55:45.063200Z

CIDER uses fipp for all projects if you set it as the default (setq cider-pprint-fn 'fipp) Does the editor you are using support something similar?

emccue 2020-09-24T20:35:24.064200Z

@paul931224 Maybe not super helpful if its set in stone, but Mongo probably isn't the best database for this

emccue 2020-09-24T20:35:44.064500Z

it sounds like you actually want strong consistency

emccue 2020-09-24T20:35:58.064900Z

and your ultimate data size won't be that huge

emccue 2020-09-24T20:36:06.065200Z

so...just use a sql database

emccue 2020-09-24T20:36:25.065500Z

then you can do that whole process in a transaction

āž• 3
emccue 2020-09-24T20:37:30.066800Z

you will run into more scaling problems trying to have what would effectively need to be a distributed lock on the reservations collection than with scaling a sql db

emccue 2020-09-24T20:41:03.068300Z

if you don't need to scale ever and really can just have a single server for all time then server side locks would be just fine

emccue 2020-09-24T20:43:00.069700Z

i know there is some degree of transaction support in mongo

emccue 2020-09-24T20:47:04.071500Z

but truthfully I don't know that much about it

NoahTheDuke 2020-09-24T21:04:41.072100Z

namespace and protocol question: i have a protocol CostFns in game.core.abilities, and then (:require [game.core.abilities :refer [CostFns]]) it in game.core. I wrote a factory function to store the records that implement these in a var, so I can pass in a keyword to get the right record out, and if I print out the calls, the var is correctly filled during compilation. However, at a later point during compilation an error is thrown, saying that No implementation of method: :cost-name of protocol: #'game.core.abilities/CostFns found for class: game.core.Click

NoahTheDuke 2020-09-24T21:09:04.072400Z

has anyone run into something like this before?

alexmiller 2020-09-24T21:10:25.072900Z

yes, you've reloaded the protocol at some point

NoahTheDuke 2020-09-24T21:10:34.073300Z

ah, okay

alexmiller 2020-09-24T21:10:51.074100Z

the protocol, when compiled, makes a Java interface and the records implement that interface

alexmiller 2020-09-24T21:11:04.074500Z

if you reload the protocol, you make a new interface (same name), and the old records don't implement it

NoahTheDuke 2020-09-24T21:11:15.074700Z

oh interesting, okay. thank you

nickt 2020-09-24T21:46:50.076500Z

hey all. Another quick question... I'd like to write a macro that takes N arguments such that if the first argument is a map literal, do nothing, otherwise inject an empty map at the front of the N arguments list. Seems straightforward enough, but how do I check the type of that first argument in a macro?

2020-09-24T21:48:43.077400Z

that's only possible if the map is a literal, you can't check the type of an arg otherwise, it's just a symbol, you don't see the value the symbol resolves to locally until runtime

2020-09-24T21:49:22.078100Z

of course the map being added to the arg list could be done at runtime, you just need to emit code that checks and modifies the arg list in that case

nickt 2020-09-24T21:49:40.078500Z

hmm ok, yea, makes sense

2020-09-24T21:50:58.079700Z

(defmacro foo-bar [& args] `(let [arg-list# (if (map? (first ~args)) ~args (cons {} ~args))] ...))

nickt 2020-09-24T21:54:57.080500Z

cool, thanks!

nickt 2020-09-24T21:56:51.081100Z

ok unrelated question: I'm aware of list? and vector?. Is there a similar predicate that is true if either list or vector?

2020-09-24T21:57:27.081400Z

perhaps you want sequential?

2020-09-24T21:57:49.081900Z

that is also true for lazy-seqs and conses, which are not lists and are false for list?

2020-09-24T21:58:58.082300Z

in fact, list? is so rarely useful I consider it a smell in code review

nickt 2020-09-24T21:59:05.082500Z

ah, awesome

nickt 2020-09-24T22:07:52.083700Z

oh, duh, map? won't work for me in that argslist check because all of the args will be maps heh. What's the idiomatic way to basically "type" a map? As in define a map as a type A or not

nickt 2020-09-24T22:08:04.083900Z

deftype?

2020-09-24T22:11:08.084400Z

you could have a special key or metadata, or use defrecord to have a map with a named type

2020-09-24T22:11:18.084700Z

how does that first map have to be different from the rest?

nickt 2020-09-24T22:34:49.085300Z

defrecord was the one! Thank you!

vncz 2020-09-24T23:32:50.085500Z

@codonnell Here it is. Likely not the best code ever, but it does the job.