Fork me on GitHub

is there a fast embedded database for clojure that persists to disk?


derby maybe...


@corasaurus-hex what do you mean by "for clojure"?


well, I mostly mean simple to use from clojure and embedded in the runtime. I suppose there's h2 as well


I considered rocksdb too, even though it's through jni. or sqlite


sqlite is "embedded" too isn't it


sure, definitely


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: 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.


thanks Andy


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


Cool, will try that, thanks


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


There's a global-fixtures thing. Not sure if circleci still uses clojure.


thought i heard their front-end is moving away from cljs but i assume their backend is still clojure heavy


Yeah that's my impression as well


Looks like it uses clojure 1.8 and lein. Might not play nice with 1.9 and deps.edn


I happen to be looking at that right now


I don't see anything global-fixtures related


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


(as opposed to yes | lein upgrade 2.9.0 or whatever)


@deadghost this is weird to say, but you can always write ordinary clojure code to setup fixtures, then run tests and tear them down


Clojure accepts a script file as input, can do arbitrary things in it


or fork the cognitect-labs/test-runner and add a fixture to it (it's 120LOC)


@ghadi like $ clj -m ns-to-setup-run-teardown-tests?


or clj dostuff.clj


can reuse all the test running machinery


yeah that can work


feels offbeat but I don't see why not


happy to consider extensions to test-runner


@alexmiller sure, let me get a basic thing working before I veer off into test-runner

Suni Masuno18:08:33

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.

Suni Masuno18:08:16

That's a neato idea, I can even limit myself to #_ just the things that vX that I just removed is using

Suni Masuno18:08:34

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?

Suni Masuno18:08:56

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.

Suni Masuno18:08:45

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.

Suni Masuno18:08:16

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

🤯 2

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

Suni Masuno19:08:08

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!

Suni Masuno20:08:49

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


OR, we’ve been passing anomalies on channels ( 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.


@jrychter fwiw, there is also a #core-async 🙂

Benny kach23:08:06

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)

Benny kach23:08:27

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