Live data from Hacker News

Zig's new plan for asynchronous programs

lwn.net

91–100 of 274 posts

Re: Zig's new plan for asynchronous programs

#91
post #57
post #20

Earlier quoted context omitted.

A channel is not just a thread-safe queue. It's a thread-safe queue that can be used in a select call. Select is the distinguishing feature, not the queuing. I don't know enough Zig to know whether you can write a bit of code that says " either pull from this queue or that queue when they are ready"; if so, then yes they are an adequate replacement, if not, no they are not. Of course even if that exact queue is not i…

If we're just arguing about the true nature of Scotsmen, isn't "select a channel" merely a convenience around awaiting a condition?

It's more akin to awaiting *any* condition from a list.

Re: Zig's new plan for asynchronous programs

#92

I think this design is very reasonable. However, I find Zig's explanation of it pretty confusing: they've taken pains to emphasize that it solves the function coloring problem, which it doesn't: it pushes I/O into an effect type, which essentially behaves as a token that callers need to retain. This is a form of coloring, albeit one that's much more ergonomic. (To my understanding this is pretty similar to how Go sol…

The function coloring problem actually comes up when you implement the async part using stackless coroutines (e.g. in Rust) or callbacks (e.g. in Javascript). Zig's new I/O does neither of those for now, so hence why it doesn't suffer from it, but at the same time it didn't "solve" the problem, it just sidestepped it by providing an implementation that has similar features but not exactly the same tradeoffs.

How are the tradeoffs meaningfully different? Imagine that, instead of passing an `Io` object around, you just had to add an `async` keyword to the function, and that was simply syntactic sugar for an implied `Io` argument, and you could use an `await` keyword as syntactic sugar to pass whatever `Io` object the caller has to the callee.

I don't see how that's not the exact same situation.

Re: Zig's new plan for asynchronous programs

#93
post #89
post #82

Earlier quoted context omitted.

> In Zig, a function that does IO can be called the same way whether or not it performs async operations or not. no, you can't, you need to pass a IO parameter

You will need to pass that for synchronous IO as well. All IO in the standard library is moving to the Io interface. Sync and async. If I want to call a function that does asynchronous IO, I'll use: foo(io, ...); If I want to call one that does synchronous IO, I'll write: foo(io, ...); If I want to express that either one of the above can be run asynchronously if possible, I'll write: io.async(foo, .{ io, ... }); If…

what about non-io code?

Re: Zig's new plan for asynchronous programs

#94
post #57
post #20

Earlier quoted context omitted.

A channel is not just a thread-safe queue. It's a thread-safe queue that can be used in a select call. Select is the distinguishing feature, not the queuing. I don't know enough Zig to know whether you can write a bit of code that says " either pull from this queue or that queue when they are ready"; if so, then yes they are an adequate replacement, if not, no they are not. Of course even if that exact queue is not i…

If we're just arguing about the true nature of Scotsmen, isn't "select a channel" merely a convenience around awaiting a condition?

This is not a "true Scotsman" argument. It's the distinctive characteristic of Go channels. Threaded queues where you can call ".get()" from another thread, but that operation is blocking and you can't try any other queues, then you can't write:

    select {
    case result := 
or any more elaborate structure.

Or, to put it a different way, when someone says "I implement Go channels in X Language" I don't look for whether they have a threaded queue but whether they have a select equivalent. Odds are that there's already a dozen "threaded queues" in X Language anyhow, but select is less common.

Again note the difference between the word "distinctive" and "unique". No individual feature of Go is unique, of course, because again, Go does not have special unique access to Go CPU opcodes that no one else can use. It's the more defining characteristic compared to the more mundane and normal threaded queue.

Of course you can implement this a number of ways. It is not equivalent to a naive condition wait, but probably with enough work you could implement them more or less with a condition, possibly with some additional compiler assistance to make it easier to use, since you'd need to be combining several together in some manner.

Re: Zig's new plan for asynchronous programs

#95
post #27

Earlier quoted context omitted.

Haskell has green threads. Plus nowadays Java also has virtual threads.

And I bet those green threads still need an IO type of some sort to encode anything non-pure, plus usually do-syntax. Comparing merely concurrent computations to I/O-async is just weird. In fact, I suspect that even those green threads already have a "colourful" type, although I can't check right now.

Pure actions can be run in parallel with https://hackage-content.haskell.org/package/parallel/docs/Co...

Impure actions use the IO monad like always in Haskell: https://hackage.haskell.org/package/base-4.21.0.0/docs/Contr... (or the higher-level async library)

I suppose an extreme version of the function coloring argument could be that all types are colors.

Re: Zig's new plan for asynchronous programs

#96
post #72
post #20

Earlier quoted context omitted.

A channel is not just a thread-safe queue. It's a thread-safe queue that can be used in a select call. Select is the distinguishing feature, not the queuing. I don't know enough Zig to know whether you can write a bit of code that says " either pull from this queue or that queue when they are ready"; if so, then yes they are an adequate replacement, if not, no they are not. Of course even if that exact queue is not i…

> I don't know enough Zig to know whether you can write a bit of code that says "either pull from this queue or that queue when they are ready"; if so, then yes they are an adequate replacement, if not, no they are not. Thanks for giving me a reason to peek into how Zig does things now. Zig has a generic select function[1] that works with futures. As is common, Blub's language feature is Zig's comptime function. Then…

Getting a simple future from multiple queues and then waiting for the first one is not a match for Go channel semantics. If you do a select on three channels, you will receive a result from one of them, but you don't get any future claim on the other two channels. Other goroutines could pick them up. And if another goroutine does get something from those channels, that is a guaranteed one-time communication and the original goroutine now can not get access to that value; the future does not "resolve".

Channel semantics don't match futures semantics. As the name implies, channels are streams, futures are a single future value that may or may not have resolved yet.

Again, I'm sure nothing stops Zig from implementing Go channels in half-a-dozen different ways, but it's definitely not as easy as "oh just wrap a future around the .get of a threaded queue".

By a similar argument it should be observed that channels don't naively implement futures either. It's fairly easy to make a future out of a channel and a couple of simple methods; I think I see about 1 library a month going by that "implements futures" in Go. But it's something that has to be done because channels aren't futures and futures aren't channels.

(Note that I'm not making any arguments about whether one or the other is better. I think such arguments are actually quite difficult because while both are quite different in practice, they also both fairly fully cover the solution space and it isn't clear to me there's globally an advantage to one or the other. But they are certainly different.)

Re: Zig's new plan for asynchronous programs

#97
post #93
post #89

Earlier quoted context omitted.

You will need to pass that for synchronous IO as well. All IO in the standard library is moving to the Io interface. Sync and async. If I want to call a function that does asynchronous IO, I'll use: foo(io, ...); If I want to call one that does synchronous IO, I'll write: foo(io, ...); If I want to express that either one of the above can be run asynchronously if possible, I'll write: io.async(foo, .{ io, ... }); If…

what about non-io code?

What about it? It gets called without an Io parameter. Same way that a function that doesn't allocate doesn't get an allocator.

I feel like you're trying to set me up for a gotcha "see, zig does color functions because it distinguishes functions that do io and those that don't!".

And yes, that's true. Zig, at least Zig code using std, will mark functions that do Io with an Io parameter. But surely you can see how that will lead to less of a split in the ecosystem compared to sync and async rust?

Re: Zig's new plan for asynchronous programs

#98

Earlier quoted context omitted.

Agreed. the Haskeller in me screams "You've just implemented the IO monad without language support".

It's not a monad because it doesn't return a description of how to carry out I/O that is performed by a separate system; it does the I/O inside the function before returning. That's a regular old interface, not a monad.

So it's the reader monad, then? ;-)

Re: Zig's new plan for asynchronous programs

#99
post #97
post #93

Earlier quoted context omitted.

what about non-io code?

What about it? It gets called without an Io parameter. Same way that a function that doesn't allocate doesn't get an allocator. I feel like you're trying to set me up for a gotcha "see, zig does color functions because it distinguishes functions that do io and those that don't!". And yes, that's true. Zig, at least Zig code using std, will mark functions that do Io with an Io parameter. But surely you can see how tha…

> But surely you can see how that will lead to less of a split in the ecosystem compared to sync and async rust?

not yet

Re: Zig's new plan for asynchronous programs

#100
post #98

Earlier quoted context omitted.

It's not a monad because it doesn't return a description of how to carry out I/O that is performed by a separate system; it does the I/O inside the function before returning. That's a regular old interface, not a monad.

So it's the reader monad, then? ;-)

[deleted]
Post reply on HN