This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-08-15
Channels
- # announcements (1)
- # beginners (101)
- # boot (13)
- # cider (38)
- # cljdoc (10)
- # cljs-dev (37)
- # cljsrn (6)
- # clojure (74)
- # clojure-dev (8)
- # clojure-europe (3)
- # clojure-italy (36)
- # clojure-losangeles (2)
- # clojure-nl (5)
- # clojure-spec (15)
- # clojure-uk (49)
- # clojuredesign-podcast (2)
- # clojurescript (52)
- # cursive (6)
- # datomic (19)
- # fulcro (35)
- # graalvm (16)
- # graphql (4)
- # kaocha (1)
- # leiningen (26)
- # luminus (3)
- # re-frame (10)
- # reagent (14)
- # ring-swagger (37)
- # rum (2)
- # schema (4)
- # shadow-cljs (148)
- # spacemacs (13)
- # specter (1)
- # sql (46)
- # tools-deps (3)
- # vim (4)
@deleted-user what do you mean by "for clojure"?
What is the idiomatic way of doing a select-keys like operation to retain only the keys with a certain namespace?
ie. (select-keys my-map "mynamespace")
Many libraries contain a filter-keys
or similar function, including medley: http://weavejester.github.io/medley/medley.core.html#var-filter-keys that could be used to achieve that effect (and many others).
That plus calling the fn namespace
on the keys to extract the namespace of the keyword, and comparing it to the desired namespace name as a string.
is print-throwable the only thing that leads pr-str to have literal newlines in results?
Hey, is there an easy way to start a Clojure repl from a gradle project? I'm probably being blind, but all the things i found lead to long dead things, like Clojuresque
Is there a nice way to do something before running all tests(setup) and do another thing after the tests(cleanup)? I know use-fixtures
can do this once per fn or once per ns.
not in clojure.test
Thinking about using https://github.com/circleci/circleci.test
thought i heard their front-end is moving away from cljs but i assume their backend is still clojure heavy
oh yeah. it's on an old version of lein and that version is annoyingly prevented from upgrading. that wasn't fun
- run:
name: upgrade Lein to 2.9.0
command: |
wget -q
chmod a+x lein
sudo mv lein /usr/local/bin
@deadghost this is weird to say, but you can always write ordinary clojure code to setup fixtures, then run tests and tear them down
happy to consider extensions to test-runner
@alexmiller sure, let me get a basic thing working before I veer off into test-runner
Ok, this is kinda a weird question... More workflow than anything.
I have an old repo made by someone(s) who left the company I got handed today. It has a cond
in it that examines a network request for a version number than runs different versions of the same function based on the version... ie
(condp = (:verison request)
1 (fun-v1 args)
2 (fun-v2 args)
3 (fun-v3 args)
4 (fun-v4 args)
5 (fun-v5 args)
6 (fun-v6 args))
But only one system can call this, and it only calls v6. Anything else will error out the other systems. So I want to remove the code form the old versions.
So far so simple. The problem... v1-v5 are often calling the same code, and often calling files with the same name in different folders, or functions with the same name in different files. Each version is effectively a different author from a different time in history, and they sometimes reused code and sometimes didn't.
So here's my real question...
How do you go about removing those functions that are depended upon by v1-5 without effecting those depended upon by v6? Can I generate some sort of dependency graph or something?Not sure if there is some subtle problem with this idea, but you could start by removing the calls to fun-v1 thru fun-v5, then remove all other code except for funv6 and the call to it. Try to compile the code, seeing a flurry of errors about undefined functions. Add those back. Repeat until no such errors. Basically, the idea is "start from empty, add what is needed to compile, stop when it compiles".
The compiler is your checker for missing functions.
#_ can be very helpful here
use #_ to take out subforms, see if a fresh repl blows up, bring back the definitions needed, etc.
That's a neato idea, I can even limit myself to #_
just the things that vX that I just removed is using
There's still effectively some manual tree traversal, but not a tone
A different question to think on -- how did you reach the conclusion that no requests are arriving other than version 6?
a LOT of digging. But the big thing is call control. This system will reject anything that doesn't have the id secret that only one other system actually has. And I have access to that other system's code and it is hard coded to v6. Asking some management it apparently once did more, but that functionality all got cut out a while ago.
And watching logs, and checking the file write outs that this thing makes (which have the version attached) show yeeeears since any v other than the latest was used.
Though I'll admit, final validation will come when I roll the system out without those endpoints and we see if anyone comes crawling outta the woodwork. I'll be damned impressed if they do, but I'll be ready with a rollback just in case.
you can also log metrics about the various v < 6 calls, and then retire the ones that have been 0 for a long time
wow. years of logs is pretty impressive evidence.
@suni_masuno backing up to what you literally asked for in the first question, lein yagni
will tell you which functions in your codebase don't have callers
if you know which cases you can comment out / remove the yagni plugin will let you know which other code was "orphaned" and likely also safe to remove
sadly it is dumb about multimethods and recoords
This code was, mostly, the first clojure work for the people who've worked on it, so I think I'll avoid multimethods, though I can't be 100%. Still, yagni should help a TON! Thanks!
Using yagni, got a question. What are the most common root functions/bindings that should be listed in a yagni init
usually for a lib you put all your API functions in there, for an app just -main
So I was just setting up my clojure env on a new machine and Sublime seems to have completely forgotten how to indent clojure for me. Has anyone else had this happen?
People using core.async, how do you implement error handling and completion status? Use a single channel with a convention/protocol on top, use multiple channels?
For context: let's say I'm accessing a database asynchronously, and I will produce a stream of values, but somebody also needs to keep the connection open while I'm reading, and sometimes there will be errors/exceptions.
Or, simpler context: I get handed a CompletableFuture
.
I know about manifold, but I'm trying to see if I can avoid pulling it in along with all its dependencies.
We usually put a Throwable object on the channel, and some throwing-take utilities from https://github.com/fullcontact/full.async
OR, we’ve been passing anomalies on channels (https://github.com/cognitect-labs/anomalies). This is somewhat “newer” for us, and I like it better
@UFQT3VCF8 Hmm. So you use a single channel for both data and exceptions.
Thanks for both pointers, these libraries are very interesting. I feel like we are missing something that CompletableFuture
packages together: status of the computation (if it's been completed or not), possible exceptions/errors, and the (possible) result.
But — if you place anomalies on your channels, then you have to detect them somehow when reading from channels. Which probably means that your channels have a protocol (you encapsulate "normal" values), right?
yes, you do need to check if the value you get off a channel is an anomaly, if you use anomalies. I think it’s preferable for its simplicity, though (also, the domain of error types in anomalies is tiny, compared to the galaxy of different exception types you can encounter)
and as far as parity to what you get from CompletableFuture
, I think manifold
is the best option (we use that too). core.async is really best for doing CSP, not for “generic” async programming, whatever “generic” means
and, the best way to distinguish anomaly or not is just (clojure.spec.alpha/valid? :cognitect.anomalies/anomaly value)
Thanks for all your advice. The pointers are really helpful, though full.async does too much for my taste, I'd rather see a smaller library which is only about handling exceptions. As for manifold, I'm still considering it, but it is a large and complex library with multiple dependencies.
Is there a reason to use transducers over reducers other than that with small collections or small operations reducers might have overhead (due concurrency) ?
reducers are still a way of consuming a collection, while transducers are agnostic to data source
(eg. you can't attach a reducer to a core.async channel)
How can I attach a transducer to core.async channel? What does that mean?
it's an optional argument to chan
after the buffer, and it means that all values that come through the chan are processed by the transducer
eg. core.async used to have >map
for mapping on channel values, that's gone now and instead we use (chan N (map f))
it does the same thing, without having to rewrite map for every context of processing data (same with filter, partition-all etc.)
so reducers are a strategy for parallel computation, transducers are a way to describe modular units of data processing abstracted from the source of the data
I assume if reducers were invented more recently, they would have used transducers