On Tue, Apr 4, 2023 at 2:22 AM Nigel Tao <nigel...@golang.org> wrote:

>
> I'd have to study mux9p for longer, but its select chooses between two
> receives, so it could possibly collapse to a single heterogenous
> channel. Indeed, both its channels are already heterogenous in some
> sense. Both its processTx and processRx methods say "switch
> m.tx.Type".
>
>
If you crank that idea to the max, you can get away with a single mailbox
for a goroutine, much like in the sense Erlang is doing it. This approach,
however, sacrifices type information which is currently being upheld by the
ability to select on multiple channels, each of which have different types.
In my experience, the concurrency primitives are malleable in many
programming languages, and you can implement one model with another, albeit
at a heavy efficiency penalty due to translation.

I wouldn't be surprised if you find that a simpler model will work in 95%
of all cases, and that you can find workarounds for the remaining 5% to the
point where you are going to ask "what's the point?" I think the answer is
"elegance and simplicity".

A view: a select statement is a synchronization of an event. A channel read
or a channel write is an event. The select statement is an algebraic concat
operation, in the sense it takes an array of such events and produces a new
event. We often think of these events as being either "we receive
something" or "we send something". But select-statements also allow for
their combination of "we either send or receive something". Sometimes,
serializing those events into a "send, then receive" or "receive, then
send" pattern is fairly easy. Sometimes, it is exceedingly hard to pull
off, and the parallel send/recv pattern is just that much more elegant and
clearer. The key problem is that sends and/or receives can block, thus
obstructing the other event from being processed. You can alleviate this by
tasting each channel through a poll. But those solutions often end up being
convoluted.

To hammer it in even more: a select statement is more than just a single
concat. It also contains a body for each event. That body allows you to
mediate between different event types, so even if the type of the channel
varies, the rest of the code doesn't have to deal with the variance.

If you want a model which works locally, non-distributed, and cranks the
above ideas even more, you should look at Concurrent ML. In that language,
events are first-class values which can be manipulated by programs. There's
no select, but you have lower level primitives which allows you to
construct one when you need it. The key difference to something like Go is
that you can dynamically build up a select as you go and then synchronize
it. In Go, such statements are static in the program, and you have to
resort to tricks where you disable channels by setting their variables to
nil. The perhaps most interesting part of CML is the `withNACK`
construction. It allows you to carry out an action if *another* event ends
up being chosen. If you squint your eyes---it has to be really really hard,
admittedly---it's a vast generalization of Go's `defer`. Where defer cleans
up on aborts in functions, withNACK cleans up after aborted events (under a
select).


-- 
J.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAGrdgiVCcGLXbZEOOfs%3DXn_6xS4MUddTxkmfkWe8e3k4sqtSdw%40mail.gmail.com.

Reply via email to