Live data from Hacker News

Zig's New Async I/O

kristoff.it

281–290 of 293 posts

Re: Zig's New Async I/O

#281
post #3

I feel that I have to point this out once again, because the article goes so far as to state that: > With this last improvement Zig has completely defeated function coloring. I disagree with this. Let's look at the 5 rules referenced in the famous "What color is your function?" article referenced here. > 1. Every function has a color Well, you don't have async/sync/red/blue anymore, but you now have IO and non-IO fun…

I have a much longer rant elsethread, but the tl;dr; is:

In some languages red can call blue, but blue cannot call red (JS). In some other languages blue can call red, but the resulting combined function is blue (traditional async with optional blocking). Finally some languages allow blue to call red and having the resulting combined function to be red (lua, scheme, go, and I believe Zig). As color is no longer a n unabstractable restriction in these languages, it no different than other kind of typing.

Re: Zig's New Async I/O

#282

Earlier quoted context omitted.

Not at all. Dependency injection is the injection of dependencies as logical parameters. The simplest and arguably best way to inject logical parameters to a segment of code is to use function parameters. You can have a complicated DI framework that involves Java class annotations and megabytes of XML, but that’s not the central idea.

> inject logical parameters to a segment of code is to use function parameters. You can have a complicated DI framework that involves Java class annotations and megabytes of XML, but that’s not the central idea. so the central idea of dependency injection, a concept with a wiki of like 5000 words [1], is just pass parameters to functions ...? i guess i'm happy to accept that (i personally DGAF about DI or whatever) b…

> so the central idea of dependency injection, a concept with a wiki of like 5000 words [1], is just pass parameters to functions...?

Specifically, parameters that refer to a dependency that is being injected.

And yeah, there are a lot of fundamentally simple ideas that can be massively overcomplicated. Let’s take a look at that Wikipedia article:

> There are several ways in which a client can receive injected services:[29]

> * Constructor injection, where dependencies are provided through a client's class constructor.

> * Method Injection, where dependencies are provided to a method only when required for specific functionality.

> * Setter injection, where the client exposes a setter method which accepts the dependency.

> * Interface injection, where the dependency's interface provides an injector method that will inject the dependency into any client passed to it.

You’ll notice that these are more or less an enumeration of ways to pass parameters into functions in object oriented programming. Most of the complexity isn’t the idea of dependency injection itself but rather in building abstractions for doing dependency injection, especially in an object-oriented language.

And yeah, a lot of the complicated versions of DI, like Spring, probably are mostly snake oil. But I object to the notion that I am peddling snake oil because I’m not advocating for anything like Spring or claiming that DI is anything more than parameterization.

Re: Zig's New Async I/O

#283
post #272

Earlier quoted context omitted.

Not at all. Dependency injection is the injection of dependencies as logical parameters. The simplest and arguably best way to inject logical parameters to a segment of code is to use function parameters. You can have a complicated DI framework that involves Java class annotations and megabytes of XML, but that’s not the central idea.

I'm sorry but if I read > most modern apps rely on some form of dependency injection then plain parameter passing is not what I'm thinking of. Especially not manually doing that to hundreds or thousands of calls.

Most forms of dependency injection are abstractions over parameter passing. If you find yourself passing the same parameters into many different function calls there are ways of abstracting that, even in Zig. It’s not going to look like Spring and if that’s a dealbreaker for you, just use Spring, it’s a free country.

Re: Zig's New Async I/O

#284
post #161

Earlier quoted context omitted.

Not quite: * Global variables still exist and can be stored to / loaded from by any code * Only convention stops a function from constructing its own `Io` * Only convention stops a function from reaching directly into low-level primitives (e.g. syscalls or libc FFI) However, in practice, we've found that such conventions tend to be fairly well-respected in most Zig code. I anticipate `Io` being no different. So, if y…

What about random number generation; is that something that will also fall under Io?

I think random numbers can safely be considered non blocking.

Re: Zig's New Async I/O

#285

I wrote a simple ssh server in zig to learn the language in my spare time. The new design makes the event loop / io much easier to reason about. Thanks Andy

Is there any chance you've published your project? It would be fun to read the code.

Re: Zig's New Async I/O

#286

Earlier quoted context omitted.

It's basically how Java does it (circa 17) as well. It's something you really can't do without a pretty significant language runtime. You also really need people working within your runtime to prefer being in your runtime. Environments that do a lot of FFI don't work well with a colorblind runtime. That's because if the little C library you call does IO then you've got an incongruous interaction that you need to worr…

Neither Java nor Go make all functions async. What they provide is stackful coroutines (or equivalently one shot continuations) that allow composing async and sync functions transparently.

Golang functions are synchronous but all goroutine code is essentially async or “coloured”.

Re: Zig's New Async I/O

#287

Earlier quoted context omitted.

> I’m not sure any langage with a sync/async split has an “async” runtime built entirely out of sync operations. You get into hairy problems of definition, but you can definitely create an "async" runtime out of "sync" operations: implement an async runtime with calls to C. C doesn't have a concept of "async", and more or less all async runtime end up like this. I've implemented Future (Rust) on a struct for a Window…

> You get into hairy problems of definition, but you can definitely create an "async" runtime out of "sync" operations: implement an async runtime with calls to C. C doesn't have a concept of "async", and more or less all async runtime end up like this. While C doesn't have async OS generally provide APIs which are non-blocking, and that is what async runtimes are implemented on top of. By sync operations I mean impl…

I've been pondering this, it feels like a brain teaser. Is it possible to create an "async" runtime out of only blocking operations?

It feels like it turns purely on what "blocking operations" are (does setting a lock bit and returning count as non-blocking?)

Re: Zig's New Async I/O

#288
post #8
post #3

I feel that I have to point this out once again, because the article goes so far as to state that: > With this last improvement Zig has completely defeated function coloring. I disagree with this. Let's look at the 5 rules referenced in the famous "What color is your function?" article referenced here. > 1. Every function has a color Well, you don't have async/sync/red/blue anymore, but you now have IO and non-IO fun…

The key difference to typical async function coloring is that `Io` isn't something you need specifically for asynchronicity; it's something which (unless you make a point to reach into very low-level primitives) you will need in order to perform any IO, including reading a file, sleeping, getting the time, etc. It's also just a value which you can keep wherever you want, rather than a special attribute/property of a…

I' scratching my head here, because many languages avoid colouring. Effectively all I think you've done is specify an interface for the event loop. Python and I expect a few other languages have pluggable event loops that use the same technique.

Granted some languages like Rust don't, or at least Rust's std library doesn't standardise the event loop interface. That has lead to what can only be described as a giant mess, because there are many async frameworks, and you have to choose. If you implement some marvelous new protocol in Rust, people can't just plug it in unless you have provided the glue for the async framework they use. Zig has managed to avoid Rust's mistake with it's Io interface, but then most async implementations do avoid it in one way or another.

What you haven't avoided is the colouring that occurs between non-async code and async code. Is the trade-off "all code shall be async"? That incurs a cost to single threaded code, as all blocking system calls now become two calls (one to do the operation, and one wait for the outcome).

Long ago Rust avoided that by deciding other whether to do a blocking call, or a schedule call followed by a wait when the system call is done. But making decision also incurs it's over overhead on each and every system call, which Rust decided was too much of an imposition.

For Rust, there is possibly a solution: monomorphisation. The compiler generates one set of code when the OS scheduler is used, and another when the process has it's own event loop. I expect they haven't done that because it's hard and disruptive. I would be impressed if Zig had done it, but I suspect it hasn't.

Re: Zig's New Async I/O

#289
post #8

Earlier quoted context omitted.

The key difference to typical async function coloring is that `Io` isn't something you need specifically for asynchronicity; it's something which (unless you make a point to reach into very low-level primitives) you will need in order to perform any IO, including reading a file, sleeping, getting the time, etc. It's also just a value which you can keep wherever you want, rather than a special attribute/property of a…

> Arguably, our solution to the problem is just to color every function async-colored. This is essentially how Golang achived color-blindness.

Golang isn't color-blind. The magic of async/await isn't that the program isn't blocked, it's that the CALLER doesn't have to be blocked. It gives the caller the flexibility to continue and synchronize at its discretion.

In Golang to avoid blocking the CALLER you'd still have to wrap the call in a Goroutine and use something like a channel(or shared mem) to communicate back to the caller.

Guess what ends up happening IRL? People create a set of functions that return channels, and a set of functions that don't for maximum flexibility. Two colors.

And that's viral much like async/await. You block on that channel? Now your caller needs to wrap you in a Goroutine. Or you have to return the/a channel. etc etc etc.

Re: Zig's New Async I/O

#290

Earlier quoted context omitted.

Not at all. Dependency injection is the injection of dependencies as logical parameters. The simplest and arguably best way to inject logical parameters to a segment of code is to use function parameters. You can have a complicated DI framework that involves Java class annotations and megabytes of XML, but that’s not the central idea.

> inject logical parameters to a segment of code is to use function parameters. You can have a complicated DI framework that involves Java class annotations and megabytes of XML, but that’s not the central idea. so the central idea of dependency injection, a concept with a wiki of like 5000 words [1], is just pass parameters to functions ...? i guess i'm happy to accept that (i personally DGAF about DI or whatever) b…

> so the central idea of dependency injection, a concept with a wiki of like 5000 words [1], is just pass parameters to functions...

... instead of functions reaching out to obtain those dependencies from globals. Yes, that is exactly what it is about. Like much of 90-00s era OOP design discourse, it's vastly overcomplicated for no good reason.

Post reply on HN