This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-10-28
Channels
- # aleph (4)
- # announcements (5)
- # babashka (28)
- # babashka-sci-dev (13)
- # beginners (63)
- # calva (76)
- # cider (113)
- # clara (7)
- # clj-kondo (42)
- # cljdoc (1)
- # clojure (170)
- # clojure-europe (20)
- # clojure-nl (17)
- # clojure-norway (3)
- # clojure-spec (12)
- # clojure-sweden (1)
- # clojure-uk (6)
- # clojurescript (55)
- # clojureverse-ops (1)
- # consulting (1)
- # core-async (9)
- # cursive (16)
- # data-science (1)
- # datascript (8)
- # datomic (27)
- # emacs (14)
- # events (1)
- # fulcro (10)
- # graphql (9)
- # gratitude (1)
- # jobs (6)
- # jobs-discuss (5)
- # leiningen (10)
- # lsp (35)
- # missionary (4)
- # nextjournal (9)
- # off-topic (46)
- # pathom (15)
- # pedestal (5)
- # polylith (37)
- # portal (15)
- # re-frame (22)
- # reagent (4)
- # reitit (5)
- # reveal (18)
- # shadow-cljs (20)
- # tools-deps (7)
- # xtdb (10)
Is there a way to use destructuring in defrecord
? I tried (defrecord Gene [& {:keys [symbol aliases transcripts]})
but it complains that the fields must be symbols. Is there a way around that?
Or should I just use a separate function as constructor?
With defrecord you declare which field that record should have. You can't use restructuring here and should use separate function to create new instance
I just upgraded from the clojure cli 1.10.2.774 to latest 1.10.3.x , and it is astounding how much faster the tool is. Just running clojure -h
is an order of magnitude faster it feels.
Thanks for saying that! I spent a lot of time on perf improvements recently.
I'm developing a full-stack Clojure Webapp and followed "Web Development in Clojure, 3rd ed." for the underlying structure. In the process of expanding and changing this to suit my needs I am serving quite large and complex data in the form of maps from the backend (I have written a loose spec for most of them) and then processing them in the front-end (mainly as an input control using a custom typeahead). Retrieval of values is done by just calling the maps with the respective keywords of the data, resulting in quite a bit of duplication in the front- and backend. After watching a few of Rich Hickey's talks and working my way through Joy of Clojure I've become unsure of whether this is a good approach.
What I want to ask is: Is it good practice okay to have the locations of my data defined multiple times in my application when a spec controls whether they conform to that shape? If not, should I put that shape in cljc files or is there a better way of declaring it? (polymorphism?)
Edit: the maps mentioned above are actually vectors of maps where the maps represent entrys of a category (e.g. a specific gene in a list of genes)
One of the big benefits of clojure.spec or other such tools in Clojure is that the same spec can be defined once in cljc and used from both
But if I need to change the spec I also need to change all places where I used a part of the spec that was changed. It seems to me the larger my application becomes the more painful changes in this system become. Should I replace the keywords with functions and define those functions all in one place? Would it be better at that point to use records and protocols?
All of those ideas will require you to change things at multiple places. Adding layers just makes more places
If you change your data, you have to change your program, that's just a consequence
The key is to stop making breaking changes and make additive changes
Don't change the type of an attribute; add a new attribute
Don't remove an attribute, just stop using it
Whenever possible, let data flow in maps and spec only what is required (let unknown attrs flow)
Build systems made to grow - Clojure gives you a ton of tools for this
I think I understand what you're saying and the implications. At least it feels like the knot in my thought process is loosening.
Having built big systems in both ways, there is no question that I prefer making the data as direct as possible with no layers between the program and the data
As Rich once said, the only thing you can do to data is ruin it :)
Is there some core function that does something like (? & fns) => [(f1) (f2) (fn) ...]
? Take any number of functions and return the result of calling all of them in order?
((juxt f1 f2 f3))
would work
or ((apply juxt fns))
if you have a coll of fns. although calling a lot of no-arg fns seems weird and implies a lot of side effecting code :)
Of course! I even made a note of juxt last time I saw you mention it here ๐ hard to remember the right one to retrieve from my brain without a bit of practice.
there are only a few function-making functions (juxt, comp, partial, every-pred, some-fn, constantly, ...)
About that side-effect point... I'm not sure whether this qualifies or not. I want to run a bunch of git queries with sh
calls and return the result. I understand that :out
is a side-effect because it's technically printing somewhere, but I really just want the result and don't care about the side-effect portion of it. Am I being pragmatic by considering these as operations without side-effects for this use case or is there a better way?
run!
is another option here and is intended for side effecting things
(run! #(%) fns)
I think ?
It's just unclear to me whether I should be considering sh
output as a side-effect here. I need the result returned in a data structure and the sh
call doesn't make any changes besides printing to stdout. A silly simplified example would be to echo 1 && echo 2
and collect the results as [1 2]
. The side-effecting functions wouldn't give me access to those results because they all return nil
(I think..).
yeah, if you need the result then run! won't help you
Maybe I should try to defer these operations and concentrate them with storing the results to local storage so the side-effects aren't quite as scattered throughout the code. Not sure. Good enough for now, but I'll give it some more thought. Thanks for the advice @alexmiller.
Is their a built in way to do this:
(let [selected-items @(rf/subscribe [selector])
selected-items (if (nil? selected-items) #{} selected-items)]
;use selected-items without throwing null error
)
?In addition to alexmiller's suggestion (which generalises to any number of let-bound things), if-let
or when-let
can be more concise if you frequently find yourself needing to bind just one thing.
But like he suggested in the other thread, it would be even better to write code that does not need to handle nil
values specially.
(let [selected-items (or @(rf/subscribe [selector]) #{})] ...)
What do you mean? Should I put it into the subscription ? So the subscription always returns either the set or an empty set.
I think the best would be to make the code that handles the subscriptions work well with nil (as most Clojure non-interop does)
but there may be concerns there I don't understand
is this idiomatic?
I feel like i am 'breaking' rules
I created function call from string.
((symbol (format "%s-ns/function" ns-prefix)) arg1)
resolve
is more what you want here, I think:
https://clojuredocs.org/clojure.core/resolve
requiring-resolve
sounds perfect for your usecase if you want the var that some symbol โpointsโ to
How is resolve different than directly invoking a symbol (effectively invoking a fn) ?
because it is looking up the key 'clojure.set/union
in the structure #{:a}
, not finding it so returning the alternative #{:b}
AAAAH very nice!!!!!
i get it
what i did worked accidentally because i had require :as something-ns
so when i created symbol something-ns/fn-name
and invoked it
(something-ns/fn-name ...)
it was resolved and pointed to the proper var
because the reader resolve
s symbols to the var. which is why the suggestion to use resolve
or requiring-resolve
is most probably what you want
weirdly i was getting java.lang.NullPointerException:
when i called this function but from repl it worked.
I will resort to case statement sadly
also that returns a function so you can in a repl just try out the require expression without calling it. youโll either get the function or nil
behavior in repl was fine. both resolve and requiring-resolve returned function i expected which called with proper arguments would do it's job but when i attempted to use that code inside an app it would throw exception. resolve would be null pointer requireing-resolve would say that there is NS on classpath