Live data from Hacker News

Zig's new plan for asynchronous programs

lwn.net

161–170 of 274 posts

Re: Zig's new plan for asynchronous programs

#162
post #17

Love it, async code is a major pita in most languages.

It's one of the things JavaScript has an easier time of than other languages due to the event driven single threaded nature of the runtime itself. They're not as powerful but they are quite useful and exceedingly ergonomic.

Re: Zig's new plan for asynchronous programs

#163

Earlier quoted context omitted.

If calling the same function with a different argument would be considered 'function coloring', every function in a program is 'colored' and the word loses its meaning ;) Zig actually also had solved the coloring problem in the old and abandondend async-await solution because the compiler simply stamped out a sync- or async-version of the same function based on the calling context (this works because everything is a…

If your functions suddenly requires (currently)unconstructable instance "Magic" which you now have to pass in from somewhere top level, that indeed suffers from the same issue as async/await. Aka function coloring. But most functions don't. They require some POD or float, string or whatever that can be easily and cheaply constructed in place.

Colors for 2 ways of doing IO vs colors for doing IO or not are so different that it’s confusing to call both of them “function coloring problem”. Only the former leads to having to duplicate everything (sync version and async version). If only the latter was a thing, no one would have coined the term and written the blog post.

Re: Zig's new plan for asynchronous programs

#164

Earlier quoted context omitted.

Yes.

Can you explain for those of us less familiar with Haskell (and monads in general)?

Reader monad is a fancy way of saying ‘have the ability to read some constant value throughout the computation’. So here they mean the io value that is passed between functions.

Re: Zig's new plan for asynchronous programs

#165
post #163

Earlier quoted context omitted.

If your functions suddenly requires (currently)unconstructable instance "Magic" which you now have to pass in from somewhere top level, that indeed suffers from the same issue as async/await. Aka function coloring. But most functions don't. They require some POD or float, string or whatever that can be easily and cheaply constructed in place.

Colors for 2 ways of doing IO vs colors for doing IO or not are so different that it’s confusing to call both of them “function coloring problem”. Only the former leads to having to duplicate everything (sync version and async version). If only the latter was a thing, no one would have coined the term and written the blog post.

IMO the problem was never about it actually doing IO or an async actions or whatever. It's about not being able to a call a async function from a sync function. Because in my experience you almost never wholesale move from sync to async everywhere. In fact I would consider that an extremely dangerous practice.

Re: Zig's new plan for asynchronous programs

#166

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…

This solves a problem for library authors which is that blocking and event-based io implementations of functionality look the same but are not actually the same so users end up complaining when you do one but not the other.

It adds a problem of needing to pass the global kind of io through a program. I think this mostly isn’t a huge problem because typical good program design has io on the periphery and so you don’t tend to need to pass this io object that ‘deep’. This is not too different from the type-system effect of IO in Haskell (except that one only does evented IO IIRC). It isn’t as bad because it only affects input types (data which can be closed over, I assume) rather than output types. Eg in Haskell you need various special functions to change from [ IO a ] to IO [ a ] but in the zig model you iterate over your list in the normal way using an io value from an outer scope.

The one case where Io-colouring was annoying to me in Haskell was adding printf debugging (there is a function to cheat the type system for this). Zig may have other solutions to that, eg a global io value for blocking io in debug builds or some global logging system.

Re: Zig's new plan for asynchronous programs

#167
post #38

Earlier quoted context omitted.

Synchronous Io also uses the Io instance now. The coloring is no longer "is it async?" it's "does it perform Io"? This allows library authors to write their code in a manner that's agnostic to the Io runtime the user chooses, synchronous, threaded, evented with stackful coroutines, evented with stackless coroutines.

Except that now your library code lost context on how it runs. If you meant it to be sync and the caller gives you an multi threaded IO your code can fail in unexpected ways.

How so? Aside from regular old thread safety issues that is.

Re: Zig's new plan for asynchronous programs

#168
post #92

Earlier quoted context omitted.

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.

It’s not the same situation because with async/await you end up with two versions of every function or library (see Rust’s std and crates like async_std, Node’s readFile and readFileSync). In Zig you always pass the “io” parameter to do I/O and you don’t have to duplicate everything.

Re: Zig's new plan for asynchronous programs

#170
post #167

Earlier quoted context omitted.

Except that now your library code lost context on how it runs. If you meant it to be sync and the caller gives you an multi threaded IO your code can fail in unexpected ways.

How so? Aside from regular old thread safety issues that is.

This is exactly the problem, thread safety. The function being supplied with std.Io needs to understand what implementation is being used to take precautions with thread safety, in case a std.Io.Threaded is used. What if this function was designed with synchrony in mind, how do you prevent it taking a penalty guarding against a threaded version of IO?
Post reply on HN