Hacker News new | ask | show | jobs
by pyrolistical 960 days ago
Agreed. I don’t know go. So I still don’t understand what this is trying to solve
1 comments

I think y'all have very fair points, for the record.

Unfortunately it is a lot easier to write documentation for an audience that shares the same context / background / experience. The README was written with an audience in mind consisting primarily of those familiar with Go (or more convoluted "communicating sequential processes" implementations), who were frustrated that things that are very easy in Go, are so much harder in JS. It's not something I considered deeply, but I was imagining that it was unlikely that someone would be searching for "channels in JS" without a base level of understanding.

I work/have worked with some pretty talented people, but (in the past) I've found it difficult to convey the value of the sorts of patterns that `ts-chan` is intended to enable, to those without first-hand experience with such patterns.

Documentation is hard :P

I’m pretty sure you could articulate how exactly this “better” pattern works versus the default “bad” one. Right now the readme is a pile of illegible jargon to me as a non-go person.
Sure, I intend to give it a shot.

I will say though, I personally get the impression that attempts at "concurrency" in JavaScript (in production code) are quite rare, which I attribute to how difficult it is.

That is to say, I don't know if there really _is_ a "default pattern".

> That is to say, I don't know if there really _is_ a "default pattern".

Here:

    const results = await Promise.all([task1(), task2()]);
Could you give a side by side comparison (with and without ts-chan) so we can better understand what kind of problem it is attempting to solve?

My understanding was that Go channels / CSP solves concurrency in a multithreaded environment where reads/writes need to coordinated, but since JavaScript is single threaded, I'm not sure I understand why they would be useful in JavaScript. In JavaScript concurrent tasks can simply communicate by writing/reading shared variables.

I am working on better examples, but they are going to take me a while, at the rate I'm currently going.

To be clear, `ts-chan` is not intended to target any use case already addressed by promises or async/await.

You mentioned CSP so I'll assume you've got context re: that topic. I believe I understand your point re: synchronisation between threads, which is fair, but I'd point out that race conditions still exist in JavaScript - I'd even say they are common, at least in my experience. It is easiest to maintain the integrity of the internal state of complex data structures when only a single logical process can mutate that state at a time.

Example in a similar vein: Firewall daemon that accepts commands over RPC, and performs system configuration, in a linear, blocking fashion, to avoid blowing things up (say it runs `iptables` and/or `nft` commands, under the hood). It would be trivial to have a select statement, with a channel per command (or just one, perhaps), receiving the input payload. In JS, the response would probably be via callback, rather than a ping-pong channel recv then send, or the like.

It wasn't a firewall daemon (although it did interact with firewalld and more), but that's exactly a pattern I've implemented in Go, for a past employer. I don't imagine anyone is keen to implement such a thing in JavaScript, but it's a pattern that applies to anything that mutates state, especially if that state is fragile or complex.

IME, race conditions are quite rare and pretty easy to solve in JS, because the flow of code execution is only susceptible to be interrupted at known locations (async function calls). Here's an example of how you could solve the problem you mentioned in a few lines of JavaScript:

    function createRunExclusive() {
      let runningTask = Promise.resolve();
      return async (asyncFn) => {
        runningTask = runningTask.then(async () => {
          return await asyncFn();
        });
        return runningTask;
      }
    }

    // Example usage:
    // The idea is that any command that should not overlap should use the same "runExclusive" function
    const runExclusive = createRunExclusive();
    function handleIpTablesCommand() {
      runExclusive(async () => {
        await doSomethingWithIpTables();
      })
    }
Although it's probably best to just use one of the queue libraries on npm. This one for example: https://www.npmjs.com/package/p-queue
> It is easiest to maintain the integrity of the internal state of complex data structures when only a single logical process can mutate that state at a time.

I agree and this is exactly what js event loop provides. So I don’t understand ts-chan

I think it would be useful to generally explain what these primitives do and how they interact with each other. A lot of JS/TS users haven’t used golang, but would appreciate a better solution if they understand it (me included).

Regarding the default vs better, a comparative example with a real concurrent task coded with/out your library would be my preferred way to understand it clearly.

I'll definitely keep that in mind, thanks :)