Discussion: "Notes on structured concurrency, or: Go statement considered harmful"

goroutines with channels solve a lot of your objections except that of handling serious errors. By convention you can pass along an error but you can’t pass it back to the caller of the channel.

You might be able to implement a nursery by convention in GoLang by forcing your GoRoutines to write their errors to an Error channel which was monitored by the nursery. By convention most GoRoutines take a “done” channel as an argument. When the nursery decides to stop processing due to an error in on one of the GoRoutines, the error monitoring GoRoutine can close the done Channel.

The fact that there is no test for “is this channel closed” is a hassle because ideally there are multiple conditions under which you would want to close everything down, and ideally you need a broadcast to do it. The hack is that any routine desiring to close the done channel has to send a message on yet another channel “Please close shit down” then the monitoring channel on that one has to close the “done” channel. Then once all these messaging channels are closed, close the “please close down” channel. Doable. but way complex to get it right.

And without any sort of templating mechanism pretty likely to have to be hand coded in every nursery.

Anyway those are my first thoughts without having tried to write all this. I am very familiar with GoLang though and use GoRoutines regularly without your issues.

Is there some discussion on how structured concurrency works with GUI frameworks?

Of course, you can do the trivial thing that you wrap the instantiation of the GUI application in a giant nursery that you pass to it so that all the event handling callbacks can live in it. Has anybody come up with some finer grained approach, and is it even desirable?

You could probably do one per window if you had some windowing framework that abstracts filtering of events by window really well but it does not seem to be common.

1 Like

I was just made aware of this post when listening to CppCast, where they’re about to talk about thr libunifex library (haven’t listened to the episode yet, decided to come and have a read first). Like others in the thread it was opening to see these thoughts in written form. Everyone knows goto is bad, yet nobody can explain it this clearly. I also didn’t know it was SO bad in earlier languages. And while I always knew somehow that concurrency frameworks had something not quite right, I couldn’t point out what exactly. The control flow black box analogy made it crystal clear.

I haven’t used Trio. While I’ve heard of it, I’d never bothered to understand what set it apart from the rest. I can’t promise I’ll be using it from now on, but the ideas definitely stay.

Another thing: your post also made me think of C’ setjmp and longjmp, which are the unbound gotos of the language. I had never seen them until I started developing extensions for the R language, which internally uses this mechanism to handle errors. Which does exactly what you mention: it completely breaks control flow, making programming these extensions very, very hard (your function might never complete, can’t rely on RAII in C++, etc).

@xialvjun
It’s what FuncSug does : No callback, no thread, just a keyword parallel (and not nursery). But , for now, it’s just for programming in the browser.