clojure-uk

A place for people in the UK, near the UK, visiting the UK, planning to visit the UK or just vaguely interested to randomly chat about things (often vi and emacs, occasionally clojure). More general the #ldnclj
jiriknesl 2021-02-19T07:55:59.395900Z

@folcon yes, I think of visual representation of things that return lazyseq and even maybe having non-lazy alternatives

jiriknesl 2021-02-19T07:56:49.396200Z

Exactly, with types this wouldn’t be a problem at all.

jiriknesl 2021-02-19T07:58:17.396500Z

Good morning

dharrigan 2021-02-19T08:48:38.396800Z

Good Morning!

djm 2021-02-19T08:54:44.397Z

👋

alexlynham 2021-02-19T09:35:59.397100Z

morning

thomas 2021-02-19T09:47:54.397300Z

mogge

mccraigmccraig 2021-02-19T10:20:58.397500Z

måning¡

danm 2021-02-19T10:38:04.397700Z

Morning

dominicm 2021-02-19T11:58:17.397800Z

Stu Halloway has some comments around the web riffing on the perception of "The most important measure for a language is how quickly a beginner can be productive". I think Rich talks about this in Design, Composition, Performance where he looks at different instruments. e.g. the Violin is not beginner friendly, but we don't need to send PRs to "fix" that, it's a tool that can be learned and you can make beautiful things in it once you do. Clojure's stance is that if there's a compromise between new-to-clojure devs and experienced-clojure-devs, the decision will always favour the latter.

1👍
2021-02-19T12:01:52.398100Z

Morn'

2021-02-19T12:05:06.401900Z

Any resources for working with large files / streaming in clojurescript? Specifically reading / building them for download client side? Should I be looking at core.async? This is within a reframe app if that helps?

alexlynham 2021-02-19T14:20:38.402Z

in our app we build some moderately sized dumps, we basically write them to an S3 bucket and give the receipient back a signed s3 link, but then we don't have to stream it directly to the client :thinking_face: not sure what we'd do if we had to stream it, probably do something that wasn't a standard http response

2021-02-19T16:17:07.402900Z

Oh streaming in this sense is managing a local file stream to an output which can be downloaded, where the file is larger than the memory chome allows...

mccraigmccraig 2021-02-19T17:04:27.403600Z

i've used the cordova file api , which i gather is based on the html 5 file api @folcon

mccraigmccraig 2021-02-19T17:05:17.404500Z

if that's the api you are looking at, it's all promise-based, so you might find it easier to use something like funcool/promesa than core.async

mccraigmccraig 2021-02-20T13:56:15.002400Z

i use both of them - i like core.async for stream-like things (e.g. a stream of events, or a stream of file buffers), but i find it awkward for promise-like things (e.g. a single http request)

mccraigmccraig 2021-02-20T13:58:36.002600Z

basically i really like the manifold programming model, which uses both promises (aka Deferred and Stream together - and it's fine to use core.async and promesa together to similar effect in cljs, although you won't get the automatic glue that manifold gives you (e.g. a reduce of a Stream returns a Deferred)

mccraigmccraig 2021-02-20T14:00:03.002800Z

i'm currently working on a thing which will give you a manifold-like model, but cross-platform and with contextual programming benefits, but it's not going to be ready for a while yet

mccraigmccraig 2021-02-20T14:03:51.003Z

for file-handling my ideal API would be based around promises, and where content streaming is required, promises of core.async chans

mccraigmccraig 2021-02-20T14:05:05.003200Z

e.g. file/exists? returns promise<bool>, file/content-stream returns promise<chan<buffer>>

2021-02-20T15:29:46.003400Z

Ah, that might not be a good fit then, the files in question are file objects that you would get from within a browser context of an upload or drag-n-drop event, so perhaps core.async might be a better fit?

2021-02-20T15:30:05.003600Z

Those events give you individual files or an array of files

mccraigmccraig 2021-02-20T18:42:31.004Z

not sure without more details - but if you've got more detail i'm happy to give you my take

2021-02-20T23:46:29.004400Z

Sure 😃... Let me know what details you need and if the explanation that I give below is insufficient 😃... I've got lots of Files[0] and a stack of transforms that I run which I'm then using to create blobs[1]. I don't quite know what transforms I'm running until later, but sometimes I need information about the file contents to work that out. Then once I build the appropriate transform stack I then run all the transforms on the file contents to build a blob which I then use to trigger a download. My current approach is to just read the file contents and then use that to work everything out, but of course for large files you can't just do that because you'll crash the browser tab with an OOM. So I'm thinking can I build a xform of any transformations I want to run on the file and then apply them to the file in chunks, using slice, or just a stream. One potential bit of fiddliness is that I might have to do this more than once, as some intermediate steps towards building the xform may require me to run the current xform state across the whole file to work out what the next step is.:thinking_face: - [0]: https://developer.mozilla.org/en-US/docs/Web/API/File - [1]: https://developer.mozilla.org/en-US/docs/Web/API/Blob

mccraigmccraig 2021-02-23T12:11:40.024600Z

well, those Blobs have a .stream() method which returns a ReadableStream - which is a stream of values very much like a core.async chan, so i would convert that ReadableStream into a core.async chan, and go from there with your xform stack ... the principle challenge will probably be in dealing with errors - iirc the ReadableStream has an error state which core.async chans don't - so you'll have to map the ReadableStream error-state to a distinguished error value on the chan

2021-02-23T12:30:00.025800Z

Thanks for that, I'll give that a go 😃, do you mind if I follow up at some point later if I hit an issue?

mccraigmccraig 2021-02-23T12:31:26.026Z

not at all 🙂

1
mccraigmccraig 2021-04-07T12:17:37.146600Z

i've not worked with long-running CPU intensive processes in js-land ... done lots on the back-end though - the approach that has stuck best is to divide work into chunks and put messages describing those chunks onto a stream/chan, then xform the stream/chan (wherein the work is done) until finally reducing it for a result

mccraigmccraig 2021-04-07T12:19:06.146800Z

we also use re-frame - i wouldn't use the re-frame event system for scheduling work though - maybe step outside to core.async and dispatch a re-frame event when you are done

mccraigmccraig 2021-04-07T12:20:39.147Z

and if you need some introspection into what's going on inside of a core.async process, define a re-frame cofx to fetch that info

2021-04-07T15:16:36.150800Z

https://clojurians.slack.com/archives/C064BA6G2/p1617798039147000?thread_ts=1613754317.404500&cid=C064BA6G2 Is there an example of this you can point to? I'm not really familiar with using cofx's as I've not really grokked what they're for and how they fit with everything else 😳...

2021-04-07T15:19:03.151100Z

https://clojurians.slack.com/archives/C064BA6G2/p1617797946146800?thread_ts=1613754317.404500&cid=C064BA6G2 I'm assuming with this you mean dispatch a reframe event that starts some long running work in core.async and then fire an event when it's done. Wouldn't there be contention between core.async and reframe? Not super sure how I can also track progress other than dispatching a progress update event to re-frame as well...

mccraigmccraig 2021-04-07T15:28:05.152700Z

cofx are inputs to a re-frame event handler from outside of re-frame - they are input side-effects in the pure world of re-frame (while fx are output side-effects). if you need your re-frame event handlers to consider any data which isn't in the event then you want a cofx (it's quite consistent - the app-db itself is a cofx, while any modification to the app-db is an fx)

mccraigmccraig 2021-04-07T15:29:29.152900Z

you could, of course, just dereference any old atom in your event-handler - but then your event-handler isn't pure and is hard to test, so instead you do the atom deref in a cofx and now your event-handler is pure and easy to test and the impurity is isolated in the cofx

mccraigmccraig 2021-04-07T15:31:02.153100Z

so if you do some async stateful stuff outside of re-frame and you want to look in on it then you can either use a cofx (e.g. with an event dispatched on a timer) or you can dispatch re-frame events from your process

mccraigmccraig 2021-04-07T15:31:57.153300Z

yes, there could be contention btw re-frame and whatever work you are doing - if that's going to be a serious issue, then you might want to look at web workers e.g. https://shadow-cljs.github.io/docs/UsersGuide.html#_web_workers

2021-05-02T14:31:09.424800Z

As far as I can tell, the only way to get introspection into the core.async process (ie tracking how much progress into a long running task has been completed) is for it to fire an re-frame dispatch event as it goes writing to the app db where it is, and then having the application display that progress marker...

mccraigmccraig 2021-05-03T09:46:46.425200Z

alternatively, keep an atom with progress/state in, and fetch from that state in a cofx, maybe from an event dispatched by a timer

jiriknesl 2021-02-19T20:34:28.406300Z

Today, we have been discussing convetions in naming functions. Like having the same naming for the same functions. We have arrived to this:

;; dump - read all values from the storage
;; load - put all values to the storage
;; set! - set value
;; find - read 0..n values from the storage
;; fetch! throws an exception when cannot find, otherwise return 1 record
;; exists? - returns boolean
What’s your way to name functions?

seancorfield 2021-02-19T20:40:39.407900Z

For me, dump and load are the wrong way round: I'm used to load meaning load-from-storage and store meaning store-to-storage -- I think we only use dump to mean display a complete in-memory structure (either on screen or write it to disk).

dharrigan 2021-02-19T20:51:22.408500Z

I'm the same, dump to me always meanings writing to file, network, somewhere more long-term, persistent.

dharrigan 2021-02-19T20:51:32.408700Z

load is to load into memory