Fork me on GitHub

would a good idiom for consuming exceptions and assertion errors that occur in go blocks be to catch the exception and put it on a dedicated channel for exceptions so it is not lost?


i just spent quite some time tracking down a problem because i never saw the exception and then realized it had happened in the go block


@ajs yes that is a very tricky part of go blocks. have you seen this article? i found it and the stuff it links to helpful.


I guess that's another way to do it. My way seems a bit easier to grock for me


seems like you’ll have to poll both channels or do an alts type take from both, no?


it depends a lot on how you structure your program


Why not just have a dedicated channel and go block for exceptions?


I don't see a need for anything fancy


if you use channels like promises and go blocks as one shot async functions then doing things like having the go block stick any exceptions on its "return" sort of makes sense


but I don't really like that structure


My go blocks are never one shot.


I usually use go blocks with loops


yeah. exactly


The exception is when I want to asynchronously handle a future when it's done.


what I like to do is treat go blocks as little services processes, and they get a input channel, an output channel, an error channel, and maybe a halt channel


Do you then wrap the entire go block in try catch?


That's what I'm thinking


it sort of depends how an why errors might occur, usually an "error" shouldn't bubble out and terminate the go block, it is just an error for a single request it is handling


If my go block is handling fast streaming data, does a try/catch block in Clojure add any overhead for performance ?


hard to say


right i was bringing my clojurescript bias and forgetting about those nasty ol’ threads 🙂


the clojure (as opposed to clojurescript) version of the go macro has some optimizations where it will emit chunks of the clojure code unaltered if there are no operations in it that need to be exposed in the state machine


so the overhead of a try/catch that doesn't contain any channel operations would be the same in the go macro vs. normal clojure code


The catch block would have a put! for handling the error, placing on an error channel


if there is a channel operation in there the go macro has to pull it all apart and emulate the jvm's try/catch/finally semantics on the state machine, which I am not sure what the performance difference would be. if I recall the emulated code pushes handler addresses on to a stack and uses the state machine to jump to them, so similar mechanically (I think) to what the jvm must do, but (wild guess) maybe an order of magnitude or two slower because it is in user code


Would put! vs >! in the go block make a difference?


I would try it as normal and benchmark it before worrying too much


I only use put! when I know for sure the channel has capacity, with put! you are bypassing the built in feedback (upstream producers halt until downstream consumers can handle msgs) that you normally get


At least on a large buffered channel your put! is less likely to fail


I rewrote the how the go macro handles try/catch a few years ago, because it was very broken in a lot of cases, so my emphasis was correctly emulating the semantics of try/catch/finally in normal clojure code

❤️ 4

@hiredman Continuing from #clojure... That's all fine, but I don't think you're addressing my concern. I will restate: You're saying the pair [channel value], which is passed as element of parameter ports, is neither a channel nor a port. Later, when one of these elements of ports is returned, it is apparently never a [channel value] pair but is always a port or perhaps a channel. Surely that should be mentioned in the docstring?


I am not sure I follow your concern, the docstring reads pretty much like what it is to me


I guess the parameter "ports" might be better called "operations"


where a single channel / ReadPort represents a take operation, and a pair of [channel value] (where channel implements WritePort) represents a put operation


alts! picks one, and returns [result-of-operation port-or-channel-that-was-operated-on]


so alts! doesn't return an element from the passed in ports


I guess that is the source of confusion?


yeah, I think so.


both places are called ports but one place is sometimes not a port but a pair that contains a port.


and I am not confused because I never bothered to read the name of the passed in parameter so I never tried to associate it with the word port in the docstring