Fork me on GitHub
#clojure
<
2021-01-27
>
pseud06:01:49

Had a fun time last night tweaking vim - like emacs, tweaking vim is an excellent place to waste hours getting ready to be productive, 10/10, highly recommended :rolling_on_the_floor_laughing: Anyway. I decided to setup Conjure, having had slightly more time with vim than last I tried it, everything made more sense and in general, the plugin is just fabulous (saying this in case its creator still lurks in here). However, in my case, I actually use CoC (conqueror of completion), a rather popular plugin for “intellisense” - code navigation, autocompletion and the like, and I encountered a bit of a problem: Using clojure-lsp I can have code navigation and refactoring tips from konda(?) etc. OR I can use coc-conjure to get the auto-completion and suggestions from the cider nrepl through which Conjure connects fed into coc — but not both..! My work-around has been to cram in deoplete, only use this for clojure and to fight with coc to disable any auto-suggestion/auto-complete functionality (just for clojure), in this way, I use CoC as a driver of the clojure-lsp process while deoplete gets its completion information through Conjure which in turn gets it from Cider. This seems hack’ish, but aside from some similar setup, e.g. another LSP plugin and then using CoC for completion, I cannot see what one should do in this case. Any input? Did I miss something stupidly obvious ? Curious to hear.

flowthing06:01:44

Don't know the answer, but you might have better luck getting help in #conjure or in the Conjure Discord (https://conjure.fun).

rickmoynihan08:01:56

Hi all, I’m trying to find an old blog post that I only vaguely remember from years back - it was a deep dive into laziness, and a very technical, detailed post. Pretty sure it was written by one of the early clojure luminaries (e.g. someone like fogus, cemerick, technomancy, ztellman), but I’ve checked their blogs etc and can’t seem to find it. I know it wasn’t stuart sierra. I seem to remember it covering the subtleties around maximal laziness, mapcat etc… With lots of good examples comparing the differences… though to be honest I can’t really remember much about the topics other than it was to do with sequences. I know I’ll recognise it when I see it though 😆 Can anyone suggest where it might be??

dusty_stick 4
delaguardo08:01:39

maybe this one - https://stuartsierra.com/2015/04/26/clojure-donts-concat it is about StackOverflow in concat

rickmoynihan08:01:28

Nope not that one, I know it definitely wasn’t by stuart sierra 🙂

rickmoynihan08:01:38

It was far more detailed than that

rickmoynihan09:01:31

I vaguely remember it having hand drawn illustrations in it; but could be wrong about that.

teodorlu12:01:56

I was thinking that Aphyr might have posted about this, but I can't find anything in particular. Here's one about sequences, which mentions lazyness: https://aphyr.com/posts/304-clojure-from-the-ground-up-sequences

teodorlu12:01:20

(I appreciate that these oldie-but-goldie posts get some new light)

rickmoynihan12:01:47

Thanks, but unfortunately that’s not the one… I think it was more about the implementation and edge cases, rather than how to use the library.

👍 4
motform09:01:01

Is there a simple way to "hook" a function so that it runs every time a form in evaluated, regardless of namespace? For example, I want to instrument core/hfun so that runs when I reevaluate either core/foo or impl/bar.

delaguardo09:01:43

you might want to have a look at this library https://github.com/alexanderjamesking/spy it implements similar idea but for testing maybe its source code can give you a hint

rickmoynihan09:01:33

Is that what motfrom is asking for? It sounds like he’s wanting to hook eval itself, not the functions. In which case you can do it by customising your repl. What repl are you using?

motform09:01:18

For the eval itself, yes. I'm currently using nrepl, but I could switch to a socket repl if that makes things easier.

Ed09:01:21

or you could just wrap the defn in a do that calls the required function?

rickmoynihan09:01:57

this is for the default clojure repl; not nREPL

rickmoynihan09:01:14

nREPL you can do it with a middleware… maybe other ways too

motform09:01:23

Ah, cool! That's fine, I have no experience hacking nrepl but i guess it would be a middleware there

delaguardo09:01:53

oh, I didn’t catch that this should be a property of the repl which is not the only way to run clojure programs

rickmoynihan09:01:21

yeah it’s certainly worth asking what your use case is. Hooking eval in the repl is only going to work in dev; though you probably don’t want to do it anywhere else 🙂

motform09:01:23

no problem! my usecase is a simple static site generator for use in the repl. The idea is that an eval could trigger the build-function. Not as nice as Oz-like live reload, but good enough for what I'm doing and would not require any (cl)js.

motform09:01:39

which also means that yes, it is purely for development use : ) Doing that in any sort of production env would be... interesing

motform09:01:54

i "enjoyed" the top heading in this repo https://github.com/technomancy/robert-hooke (obviously a different thing, but still)

rickmoynihan09:01:33

I’m not convinced eval granularity is going to align with wanting to rebuild a site, but knock yourself out 🙂

motform09:01:29

No, that's a fair point. I'm not sure either.

rickmoynihan09:01:58

It sounds like a bad idea to me

motform09:01:24

rebuilding is trivial so time is not the issue, but it would be nice to be able to control rebuilds to certains namespaces, like the one I'm using for garden

motform09:01:33

and for some templates

rickmoynihan09:01:47

You could just call rebuild yourself at the REPL… or set up a filesystem watch to rebuild on save

rickmoynihan09:01:47

Personally I’d be tempted to do something like sticking a rebuild function in user.clj and just run (user/rebuild) which will then work from any namespace when you want to rebuild.

motform09:01:38

that's what I'm doing right now, calling the rebuild and then refreshing the browser with a watch. but calling that rebuild requires navigating to a different file and navigating to that form, which adds some friction when you are doing things like editing css or smaller template changes

rickmoynihan09:01:31

use an editor hotkey to send the form to the repl

motform09:01:54

having it in user is not a bad idea. idealy, one could make an emacs keybind to send that eval (user/rebuild) in the repl without having to be on in that specific place

motform09:01:59

that's what I'm doing right now, calling the rebuild and then refreshing the browser with a watch. but calling that rebuild requires navigating to a different file and navigating to that form, which adds some friction when you are doing things like editing css or smaller template changes

motform09:01:13

(messages should be in the reverse order)

Hagenek12:01:38

Anyone familiar with speclj ? I am getting this error after setting up a new project with lein new speclj and then running lein test.

Exception in thread "main" java.io.FileNotFoundException: Could not locate speclj__init.class or speclj.clj on classpath., compiling:(clojure_functions/reduce_spec.clj:1:1)
I also see that it is using Clojure 1.8.0, is there a newer framework that I should use instead for BDD/TDD? EDIT: Switched over to trying Midje now, it seems more like what I am looking for.

delaguardo12:01:20

could you check if your project.clj has speclj declared as dependency for dev profile?

Hagenek12:01:23

my project.clj: (_defproject_ clojure-functions "0.1.0-SNAPSHOT"   _:description_ "FIXME: write description"   _:url_ ""   _:license_ {_:name_ "Eclipse Public License"             _:url_ ""}   _:main_ clojure-functions.core   _:dependencies_ [[org.clojure/clojure "1.8.0"]]   _:profiles_ {_:dev_ {_:dependencies_ [[speclj "3.3.2"]]}}   _:plugins_ [[speclj "3.3.2"]]   _:test-paths_ ["spec"])

delaguardo12:01:39

did you run lein test or lein spec ?

delaguardo12:01:28

you should use lein spec instead I think this is the most convenient way to run specs

Hagenek12:01:56

Ok! I guess I dont know the difference between spec and test 😃

delaguardo12:01:37

lein test is an option of leiningen itself speclj introduce one more option to run itself

✌️ 4
Hagenek12:01:46

Yes, and lein test is dependant on the :main NS file in the project file. After changing that to the correct (from clojure-functions.core to clojure.functions.reduce) the lein test gave me the correct error I think

Hagenek12:01:11

Well well I got it working now, thanks a lot 😃 I should have read the documentation more thoroughly, I have a tendency to expect things to just work a certain way

delaguardo12:01:46

that is ok ) there are no persons who knows everything) I also learned that difference just now)

Adam Helins13:01:31

Will this always be true? That no new map is created when a value is updated to an identical one?

(def m {:a 42})

(identical? m
            (assoc m :a 42))

Alex Miller (Clojure team)13:01:32

sorry, I misread, no I would not guarantee that

Alex Miller (Clojure team)13:01:12

I would guarantee they are equal

Alex Miller (Clojure team)13:01:04

but whether they are identical is an implementation question

Adam Helins13:01:16

Right, so when remaining 'identical' is important, it is best to get and assoc if needed rather than using update (same applies to xxx-in variants)

Alex Miller (Clojure team)13:01:51

I'd say it's bad to rely on identity in the first place

Alex Miller (Clojure team)13:01:57

and then you don't care

Adam Helins13:01:03

In the grand scheme of things yes. I am wondering about some possible optimizations for a project but otherwise I agree this would be too much of a burden.

vlaaad13:01:02

(update m :key identity) does not return identical result on records btw @adam678

👍 4
Alex Miller (Clojure team)13:01:56

current dev environment results from 2021 Clojure survey - still time to register your own choices! https://www.surveymonkey.com/r/clojure2021

👍 11
sublimetext 4
calva 3
kirill.salykin15:01:46

Hi, please advice how I can split byte-array into two byte-arrays (based on index) basically i want to split ouput of this

(defn random-bytes
  [size]
  (let [seed (byte-array size)]
    (.nextBytes (SecureRandom.) seed)
    seed))
thanks

andy.fingerhut15:01:37

You can create two new byte-array objects (which are the same as Java arrays with primitive type byte for the elements) with the lengths of the two pieces you want, and copy the parts of the original array into those two new arrays. If this is a hot inner loop, you can do the copying via the JVM method call System/arrayCopy. You could also write a loop in Clojure over the indexes of the array you want to copy, and copy the bytes one at a time in that loop.

🙏 4
Alex Miller (Clojure team)15:01:09

also see newer java.util.Arrays

🙏 4
andy.fingerhut15:01:34

Don't think I'd used the methods of that class before. copyOfRange looks useful for this purpose.

clyfe15:01:35

Clojure homebrew install says 1.10.2.774 but run says 1.10.1 details in thread.

grazfather15:01:23

then try again

clyfe15:01:32

> ➜ ~ hash -d clj > hash: no such directory name: clj

delaguardo16:01:01

clojure version might be overwritten by local deps.edn check if you have it in $HOME/.clojure/deps.edn

🎯 4
👍 4
hyper-clap 4
Alex Miller (Clojure team)16:01:25

clojure version is whatever dep you've declared

Alex Miller (Clojure team)16:01:41

new 1.10.2.x wil ldefault to 1.10.2 in root, but you can override in user or project

Alex Miller (Clojure team)16:01:58

you can use any clojure tool version with any clojure version

seancorfield18:01:18

@UCCHXTXV4 Just as a follow-up to that, if you look at my user-level deps.edn file, you'll see I have aliases for every version of Clojure all the way back to 1.0 (and three different aliases for the specific sub-versions of Clojure 1.10): https://github.com/seancorfield/dot-clojure/blob/develop/deps.edn#L171-L188

seancorfield18:01:43

That can be very useful for testing code against several different versions of Clojure, via the CLI.

👍 3
matheusashton18:01:47

Hello! I'm not sure if here is the right place, and if isn't I'm sorry in advance, but can anybody help me to understand a problem? I have this function:

(ns core.reader
  (:require [ :as io]))

(defn read-lines
  "reads an input and returns a ISeq of the lines"
  [input]
  (line-seq (io/reader input)))
receiving *in* as argument and I'm testing it like this:
(ns core.reader-test
  (:require [core.reader :as reader]
            [clojure.test :refer :all]))

(deftest core-reader-test
  (testing "read from stdin"
    (let [result (with-in-str (reader/read-lines *in*) "is\n42")]
      (is (= "is" (first result)))
      (is (= "42" (last result))))))
but when I run lein test the test hangs waiting for a input, in theory with-in-str should provide data to stdin and the test should not hang, can somebody spot what am I doing wrong?

noisesmith18:01:39

@matheusashton have you tried adding a final newline?

matheusashton18:01:11

hmmm no, I'll try

noisesmith18:01:53

@matheusashton never mind- you need a doall, or else the read-lines executes outside the with-in-str body

noisesmith18:01:05

laziness plus dynamic bindings are a bad mix

noisesmith19:01:19

but that still isn't unblocking it...

noisesmith19:01:58

@matheusashton also you have the args of with-in-str flipped

dpsutton19:01:48

I’d also make a my own output stream and not muck about with “in

noisesmith19:01:10

(cmd)user=> (with-in-str "is\n42" (doall (read-lines *in*)))
("is" "42")
(cmd)user=> (with-in-str "is\n42" (read-lines *in*))
Error printing return value (IOException) at java.io.PushbackReader/ensureOpen (PushbackReader.java:73).

noisesmith19:01:23

@dpsutton inputstream, surely

dpsutton19:01:56

Yeah. I always get the terms backwards. I always forget if output stream has output or accepts output

noisesmith19:01:21

@dpsutton my mental model is that everything is from the perspective of the object as a first person entity

noisesmith19:01:29

if you can call a read method, it's an input stream

dpsutton19:01:57

That makes sense. I think I put myself as the consumer and think “I need output from something. Ah a stream”

dpsutton19:01:12

But I’ll probably remember it now so thanks

noisesmith19:01:16

but that's projecting! it's your input

noisesmith19:01:19

it's someone else's output

noisesmith19:01:08

also there are things like StringReader that are really nobody's "output" per se, just a view of their data as if it were

Mno19:01:05

Sounds like a proverb: "one man's output is another man's input."

noisesmith19:01:26

@matheusashton I think this is simpler than what you are doing currently

user=> (read-lines (java.io.StringReader. "is\n42"))
("is" "42")

matheusashton19:01:43

@noisesmith thanks! I'll try to fix the things that you've pointed, the input of my program will be the contents of a file (I cannot read the file inside the program because I don't know the filename) so I need to read it from *in* , I was trying to make like an integration test, that's why I tried to dynamic bind *in* , I run my program like lein run < file

noisesmith19:01:33

@matheusashton my example above makes it read from a string, you don't need to send a string to in, then read in, you can just read from the string

noisesmith19:01:35

maybe use with-in-str if you need to test -main, but usually I'd make sure -main is trivial and test the individual components in ways that don't require process level resources

matheusashton19:01:50

yes, but I was trying to make an integration test, simulating the real behaviour

noisesmith19:01:19

StringReader is as real as *in* is, and also simpler

noisesmith19:01:09

in this instance, it's simpler because *in* changes value as your object changes scope, and thanks to laziness your result would change scope before being realized if you didn't force it

noisesmith19:01:05

as a big picture example, I'd set things up like this: (defn app [stream] ...) (defn -main [& args] (app *in*))

noisesmith19:01:36

where "app" has all the logic aside from implementation details (Iike which specific reader you are reading lines from)

noisesmith19:01:18

now app can be tested without relying on global / process level state like *in*

matheusashton19:01:01

Thank you very much!

noisesmith19:01:48

this pattern makes testing much easier (but it's only as good as the quality of your stubs - swapping one reader for another is great, your hand made stub for your protocol might be iffier...)

matheusashton19:01:59

also, my -main is like this:

(defn -main
  [& args]
  (->> *in*
       (read-lines)
       (map parse-json)
       (map println)))
but if I try to lein run < file it reads the lines but doesn't print parsed maps, is this something about lazyness too?

matheusashton19:01:19

parse-json is simply cheshire's parse-string

noisesmith19:01:48

right, nothing is consuming the return value of map, so why would it calculate anything?

noisesmith19:01:59

perhaps you want (run! println) instead at the end

matheusashton19:01:35

oh right, it doesn't realize the whole pipe until something needs right?

noisesmith19:01:41

@matheusashton right, because every function in the pipeline is lazy, it doesn't promise to calculate any more results than are consumed, and in the case of -main when not run from a repl, nobody consumes it

noisesmith19:01:15

the repl consumes it in order to print (and would give you a big annoying list of nils from each println call)

matheusashton19:01:15

ok, thanks! Learned a lot today 😄

richiardiandrea19:01:18

Hi all, long time ago, I was using a library that could generate HTTP call functions from clojure.specs. I do not remember the name now though. Is anybody using something like that?

clyfe19:01:06

swagger? martian?

richiardiandrea19:01:32

ah martian! Thank you 😄

Adam Helins20:01:42

Calling clojure.tools.namespace.repl/refresh in a macro used in CLJS prints an error (ie. :error-while-loading some.namespace) but the rest of the macro continues. No exception is thrown and clojure.core/*e is unbounded. Any idea how to retrieve the error? Right now I throw the exception myself in some.namespace so I know what is going on. I guess that the macro and refresh are not executed on the same thread but I don't know why (since refresh is called from the macro).

hiredman20:01:21

*e does not have a binding established when you are compiling your clojurescript, so refresh cannot set! It

Adam Helins20:01:58

@hiredman Oh right, it looks a bit weird but (binding [clojure.core/*e nil] ...) works, thanks!

dsp21:01:27

hi folks. does anyone have any experience with jdbc and hugsql? i am looking at the docs and trying to figure out how to wrap inserts in a transaction. the docs are stated as: https://www.hugsql.org/#using-transactions -- however it does not specify how to actually create a transaction. looking at https://github.com/funcool/clojure.jdbc/blob/master/src/jdbc/transaction.clj was not so enlightening either. maybe someone has an idea? i am trying to concurrently iterate on a collection of data and want to insert transformed data to a sqlite database. sqlite inserts should be wrapped in a transaction for performance reasons, and to avoid errors like "[SQLITE_BUSY] The database file is locked (database is locked)". i am using a manifold stream (like an async channel) to put to a thread that batches inserts into X amount before committing, or after a timeout is reached. i'm using hugsql so would like to take the data in and construct a transaction with the various inserts in and commit after a certain time is reached or a certain amount of inserts is fetched from the stream. any input welcome!

dsp21:01:54

doh, figured it out. with-db-transaction is not a function but a macro, so of course the spec did not make immediate sense. the parameters, [tx db], do not require a tx variable to be created beforehand but instead set a binding within the body, so tx is a transaction created from db and tx takes the place of db in any hugsql calls. lisp syntax is magical but at times confusing without clear idiot-proof commentary.

hiredman21:01:07

funcool's clojure.jdbc is also not the library you want to be using

hiredman21:01:16

funcool's clojure.jdbc has a bit of a cloud over it since some of the early code for the project looks like it could just be copied and pasted from clojure.java.jdbc (in violation of clojure.java.jdbc's license), reading funcool's docs my guess is their position is something like "clojure.jdbc is an implementation of the same api as clojure.java.jdbc so their are bound to be similarities" , but it's not a good look

noisesmith21:01:55

also they picked a name that used to be a common shorthand used in the community for the library they forked claim to have rewritten from scratch

hiredman21:01:38

yes, and rich has indicated clojure.* belongs to him as far as namespaces go

seancorfield21:01:35

I can link to the Google Groups discussion about the clojure.jdbc author and the whole copying code and stripping all the license and copyright notices...

seancorfield21:01:57

It still burns that someone would steal my code and pass it off as their own.

seancorfield21:01:19

But at this point, my main argument about funcool's clojure.jdbc is that it is unmaintained.

seancorfield21:01:51

HugSQL supports next.jdbc. And next.jdbc's documentation has a getting started guide for HugSQL. So that's the official recommendation.

dsp22:01:56

thanks. my code is old, spent 2020 not really functional 😄 next.jdbc is definitely something i want to pick up. and yes, that was a mis-google, i am indeed using clojure.java.jdbc.

dsp22:01:11

am also a little worried about using ztellman's manifold. seems zach is particularly busy/inactive lately, and noticed that manifold streams try-take! seems to increment :pending-takes continuously even if timeout was reached, not resetting it.

enki.buffers> (def y (stream/stream))
#'enki.buffers/y
enki.buffers> (dotimes [n 16384] (stream/try-take! y 1))
nil
enki.buffers> y
<< stream: {:pending-puts 0, :drained? false, :buffer-size 0, :permanent? false, :type "manifold", :sink? true, :closed? false, :pending-takes 16384, :buffer-capacity 0, :source? true} >>
enki.buffers> (stream/try-take! y 1)
Jan 27, 2021 11:29:29 PM clojure.tools.logging$eval451$fn__455 invoke
WARNING: excessive pending takes (> 16384), closing stream
java.lang.IllegalStateException
	at manifold.stream.default.Stream.take(default.clj:234)
	at enki.buffers$eval38629.invokeStatic(form-init9188607286898067210.clj:17367)
	at enki.buffers$eval38629.invoke(form-init9188607286898067210.clj:17367)
	at clojure.lang.Compiler.eval(Compiler.java:7177)
	at clojure.lang.Compiler.eval(Compiler.java:7132)
	at clojure.core$eval.invokeStatic(core.clj:3214)
	at clojure.core$eval.invoke(core.clj:3210)
	at nrepl.middleware.interruptible_eval$evaluate$fn__29511$fn__29512.invoke(interruptible_eval.clj:87)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.AFn.applyTo(AFn.java:144)
	at clojure.core$apply.invokeStatic(core.clj:665)
	at clojure.core$with_bindings_STAR_.invokeStatic(core.clj:1973)
	at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1973)
	at clojure.lang.RestFn.invoke(RestFn.java:425)
	at nrepl.middleware.interruptible_eval$evaluate$fn__29511.invoke(interruptible_eval.clj:87)
	at clojure.main$repl$read_eval_print__9086$fn__9089.invoke(main.clj:437)
	at clojure.main$repl$read_eval_print__9086.invoke(main.clj:437)
	at clojure.main$repl$fn__9095.invoke(main.clj:458)
	at clojure.main$repl.invokeStatic(main.clj:458)
	at clojure.main$repl.doInvoke(main.clj:368)
	at clojure.lang.RestFn.invoke(RestFn.java:1523)
	at nrepl.middleware.interruptible_eval$evaluate.invokeStatic(interruptible_eval.clj:84)
	at nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:56)
	at nrepl.middleware.interruptible_eval$interruptible_eval$fn__29542$fn__29546.invoke(interruptible_eval.clj:152)
	at clojure.lang.AFn.run(AFn.java:22)
	at nrepl.middleware.session$session_exec$main_loop__29609$fn__29613.invoke(session.clj:202)
	at nrepl.middleware.session$session_exec$main_loop__29609.invoke(session.clj:201)
	at clojure.lang.AFn.run(AFn.java:22)
	at java.base/java.lang.Thread.run(Thread.java:832)

#<SuccessDeferred@11f12ad4: false>
enki.buffers> (def y (stream/stream))
#'enki.buffers/y
enki.buffers> (dotimes [n 16384] (stream/try-take! y 1))
nil
enki.buffers> (stream/put! y 1)
#<Deferred@50a88030: :not-delivered>
enki.buffers> (stream/try-take! y 1)
#<SuccessDeferred@6429f73e: 1>
enki.buffers> y
<< stream: {:pending-puts 0, :drained? false, :buffer-size 0, :permanent? false, :type "manifold", :sink? true, :closed? false, :pending-takes 0, :buffer-capacity 0, :source? true} >>
I would expect that takes that timed out (so would never actually fetch from the stream) would not cause this sort of pressure and would clear from the queue. i'll fire off an email.

seancorfield22:01:37

Manifold has just transferred to the #clj-commons organization and a new maintainer is coming up to speed...

🎉 9
seancorfield22:01:36

So you could try asking in that channel or open an issue at https://github.com/clj-commons/manifold

dsp22:01:04

Thanks. Yes, will open an issue and may well look at fixing it myself when it's daylight.

hiredman22:01:54

I think I just wrote a (as of yet not applied) patch (really a series of patches) for something very like this in core.async.

hiredman22:01:36

and it is exactly that, when you have non-deterministic choice, in this case get a value from this stream or timeout, it is not enough to commit to one of the choices, you also need to go back and cleanup the choice not taken

hiredman22:01:28

core.async has some code that is run on every put/take/close of a channel that prevents build ups of non-active handlers, but if you are doing operations on channels that don't get a lot of operations (commonly timeout channels, and timeouts have other issues that make this worse) channels can hold on to handlers (and any closed over values) longer then they should

dsp22:01:30

my use case is fetching data to add to sqlite transactions in a separate thread. concurrent inserts fail due to locking, so using a channel to batch inserts is a workaround. however i do not want to specifically wait for N inserts, rather flush on N or after X seconds (to avoid losing data or delays to commits). so a way to either fetch, or time out & commit & loop, is the approach i was going for.

dsp22:01:07

it's been ~1 year or so since i've touched this, or the ecosystem, so i'll have a look around at what is available and how to best approach it. for now, it is midnight, and tomorrow i have work. 🙂 cheers

hiredman23:01:46

depending on this that and the other you might be fine with using a java.util.concurrent.LinkedBlockingQueue and passing a timeout to the poll method instead of a manifold stream

hiredman23:01:43

mmm, yeah, not actually like the core.async timeouts issue I was thinking, manifold just needs to scan pending puts for realized defers

hiredman23:01:03

(and remove them)