Hacker News new | ask | show | jobs
by jerf 1233 days ago
The real essence of Go channels is their ability to participate in the built-in select keyword. Of course, Go does not have access to any magic CPU instructions that make it something Go can uniquely do. But anything that wants to be "Go channels but in X" need to be implementing select, not a send operation. Send operations are easy. And a useful primitive! Way back in the day, Queue in Python was the way to communicate between green threads. But you don't have "Go channels" without select.

Whether that is possible in JavaScript, I don't know. It is possible in a heavy-runtime language to be so locked down that it is either impossible to implement, or impossible to implement with acceptable performance, and I'm not into Node enough to know.

(To be clear, such a thing is not a criticism necessarily. I'm not sure if you could implement select efficiently or correctly from within pure Go, either, if it did not already exist. There's a lot of runtime integration it has that is not exposed any other way. It is s perfectly viable design decision to build a runtime environment that does not give that level of access to the CPU without custom assembly or C or something.)

4 comments

Disclaimer: I am the author of this library [1].

A few days ago, I ported ocaml/Event [2] to JavaScript, which provides concurrent ML-style synchronization operations.

It is possible to implement `Channel` and `select` in JS, but it is not easy to provide an idiomatic API and integrate it with the Promise ecosystem.

[1]: https://github.com/dhcmrlchtdj/sync-op [2]: https://ocaml.org/api/Event.html

I took a stab at this a while back using an object to represent the possible resolutions. The keys of the object become a signal upon resolution that indicates which branch fired. https://github.com/ggoodman/channels#select-key-string-chann...

Ultimately though, I don't believe that channels are an abstraction that makes sense in JavaScript's concurrency model. Go's contexts, on the other hand, would be a huge improvement over AbortController and AbortSignal.

JavaScript has Promise.race, which is effectively the same thing (from a set of Promises, return as soon as the first one resolves).
> The real essence of Go channels is their ability to participate in the built-in select keyword.

Select is similar to a function in plan 9's threading library[1] (which is part of the Go lineage) called alt(). To use it you stick it in a switch like so: switch(alt(alts)){}. Select{} is syntactic sugar for some alt like functionality. Of course the programmer is responsible for setting up the alt structure and the channels it contains. Overall its a great library and I love working with thread(2).

See this wonderful article on Go' history in code for comparisons between Go, Limbo, Plan 9 C and Alef: https://seh.dev/go-legacy/

[1] http://man.postnix.pw/9front/2/thread

Might as well add a link to the source (that 9front repo is outdated, don't touch it): https://github.com/mischief/9problems/tree/master/sys/src/li...

Additionally, the approach in the article doesn't support anything like unbuffered channels, which is the default (for good reason) in Go. Even for a first approximation, the return type of `write` needs to be `Promise<void>`. So even the send operation is not quite right.