Most active commenters
  • ryandv(3)

←back to thread

292 points kristoff_it | 14 comments | | HN request time: 0.449s | source | bottom
Show context
dvt ◴[] No.44610616[source]
"Asynchrony" is a very bad word for this and we already have a very well-defined mathematical one: commutativity. Some operations are commutative (order does not matter: addition, multiplication, etc.), while others are non-commutative (order does matter: subtraction, division, etc.).

    try io.asyncConcurrent(Server.accept, .{server, io});
    io.async(Cient.connect, .{client, io});
Usually, ordering of operations in code is indicated by the line number (first line happens before the second line, and so on), but I understand that this might fly out the window in async code. So, my gut tells me this would be better achieved with the (shudder) `.then(...)` paradigm. It sucks, but better the devil you know than the devil you don't.

As written, `asyncConcurrent(...)` is confusing as shit, and unless you memorize this blog post, you'll have no idea what this code means. I get that Zig (like Rust, which I really like fwiw) is trying all kinds of new hipster things, but half the time they just end up being unintuitive and confusing. Either implement (async-based) commutativity/operation ordering somehow (like Rust's lifetimes maybe?) or just use what people are already used to.

replies(10): >>44610771 #>>44610939 #>>44612125 #>>44612190 #>>44612605 #>>44612656 #>>44612932 #>>44613047 #>>44613470 #>>44615786 #
1. ryandv ◴[] No.44610771[source]
Strictly speaking commutativity is defined over (binary) operations - so if one were to say that two async statements (e.g. connect/accept) are commutative, I would have to ask, "under what operation?"

Currently my best answer for this is the bind (>>=) operator (including, incidentally, one of its instances, `.then(...)`), but this is just fuzzy intuition if anything at all.

replies(6): >>44610835 #>>44610926 #>>44610969 #>>44611560 #>>44612207 #>>44616773 #
2. dvt ◴[] No.44610835[source]
Commutative operations (all of them I think?) are trivially generalized to n-ary operations (in fact, we do this via ∑ and ∏, in the case of addition and multiplication, respectively). You're right that the question of what "operation" we're dealing with here is a bit hazy; but I'd wager that it's probably in the family of the increment operation (N++ === N + 1 = 1 + N) since we're constantly evaluating the next line of code, like the head of a Turing machine.

Edit: maybe it's actually implication? Since the previous line(s) logically imply the next. L_0 → L_1 → L_2 → L_n? Though this is non-commutative. Not sure, it's been a few years since my last metalogic class :P

replies(2): >>44611346 #>>44613955 #
3. benreesman ◴[] No.44610926[source]
It's a good intuition. This has been studied extensively, the composition rule that is lax enough to permit arbitrary effects but strict enough to guarantee this class of outcomes is (>>=). We can keep trying to cheat this as long as we want, but it's bind.
4. xscott ◴[] No.44610969[source]
> "under what operation?"

You could treat the semicolon as an operator, and just like multiplication over matrices, it's only commutative for a subset of the general type.

replies(2): >>44610980 #>>44612012 #
5. ryandv ◴[] No.44610980[source]
Right, exactly. It's been said that (>>=) is a programmable semicolon.

[0] https://news.ycombinator.com/item?id=21715426

6. senderista ◴[] No.44611346[source]
Generalizing an associative binary op to an n-ary op just requires an identity element Id (which isn't always obvious, e.g. Id_AND=true but Id_OR=false).
replies(2): >>44612004 #>>44612390 #
7. noduerme ◴[] No.44611560[source]
`.then()` is ugly, `await` is pretty, but wouldn't the critical part to guarantee commutivity less than guaranteed order (in js) be the `Promise.all([])` part?
8. singularity2001 ◴[] No.44612004{3}[source]
Identity is nop / pass
9. singularity2001 ◴[] No.44612012[source]
or carrots return/new line For that matter
10. Nevermark ◴[] No.44612207[source]
The "operator" in this case would be the CPU executing 2 or N procedures (or functions).

Commutivity is a very light weight pattern, and so is correctly applicable to many things, and at any level of operation, as long as the context is clear.

11. JadeNB ◴[] No.44612390{3}[source]
> Generalizing an associative binary op to an n-ary op just requires an identity element Id (which isn't always obvious, e.g. Id_AND=true but Id_OR=false).

Only for n = 0, I think. Otherwise, generalizing associative binary f_2 to f_n for all positive integers n is easily done inductively by f_1(x) = x and f_{n + 1}(x_1, ..., x_n, x_{n + 1}) = f_2(f_n(x_1, ..., x_n), x_{n + 1}), with no need to refer to an identity. (In fact, the definition makes sense even if f_2 isn't associative, but is probably less useful because of the arbitrary choice to "bracket to the left.")

12. dwattttt ◴[] No.44613955[source]
Implication sounds right. With no further analysis, running each line in order is correct (for whatever "order" is defined by a language, let's assume imperative).

A compiler could recognise that e.g. L_2 doesn't depend on L_1, and would be free to reorder them. And compilers do recognise this in terms of data dependence of operations.

13. jhanschoo ◴[] No.44616773[source]
Under function composition `;`, where both the LHS and RHS are viewed as functions operating on the whole environment state.
replies(1): >>44616923 #
14. ryandv ◴[] No.44616923[source]
Right; though it's a special kind of function composition (Kleisli composition) and often presented in a different form (bind, >>=).