Live data from Hacker News

Zig's New Async I/O

kristoff.it

271–280 of 293 posts

Re: Zig's New Async I/O

#271
post #24
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…

> It's quite rare for a function to unexpectedly gain a dependency on ... If this was true in general, the function coloring problem wouldn't be talked about. However, the second point is more interesting. I think there's a bit of a Stockholm syndrome thing here with Zig programmers and Allocator. It's likely that Zig programmers won't mind passing around an extra param. If anything, it would make sense to me to have…

Stockholm syndrome? Many years ago, I was specifically wanting a programming language where I could specify an allocator as a parameter! That's one of Zig's selling points.

Re: Zig's New Async I/O

#272

Earlier quoted context omitted.

This is like saying arithmetic is a form of calculus, the simplest form. Ie it reduces the concept (DI) to a meaningless tautology.

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.

Re: Zig's New Async I/O

#273
post #229
post #68

Earlier quoted context omitted.

That is lovely to hear. I think the general conscious is that not a single programming language has done Async right. So people are a little sceptical. But Andrew and the team so far seems to have the do it right mentality. So I guess people should be a little more optimistic. Cant wait for 0.15 coming out soon.

What is wrong with async in JS?

single threaded, memory requirements, function coloring

Re: Zig's New Async I/O

#274
post #270

Earlier quoted context omitted.

but that's not even the case, because it's certainly possible to write a function that receives an object that holds onto an io (and uses it in its vtable calls) that equally well receives an object that doesn't have anything to do with io [0]. The consumers of those objects don't have to care, so there's no coloring. [0] and this isn't even really a theoretical matter, having colorblind object passing is extremely u…

I think in practice the caller still needs to know. If I call `a.foo()` but `a` has and is using a stackless coroutine IO but the caller is being executed from a green thread IO then as was said before, I'm hitting UB. But, I do like that you could skip/mock IO for instance. That's pretty neat.

here is example code. you wont "use the wrong io".

    const VTable = struct {
      f: &fn (*VTable) void,
    };

    const A = struct {
      io: IO,
      v: VTable = .{ .f = &A.uses_io },
      fn uses_io(this: *VTable) void {
        const self: *A = @fieldParentPtr(.v, this);
        self.io.some_io_fn(...);
      }
    };

    const B = struct{v: VTable = .{.f = &void_fn}};
    fn void_fn(_: *VTable) void {}

    pub fn calls_vtable(v: VTable) {
      v.f()
    }

Re: Zig's New Async I/O

#275
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…

Colouring every function async-coloured by default is something that's been attempted in the past; it was called "threads". The innovation of async over threads is simply to allocate call stack frames on the heap, in linked lists or linked DAGs instead of fixed-size chunks. This sounds inefficient, and it is: indexing a fixed block of memory is much cheaper. It comes with many advantages as well: each "thread" only o…

And threads are just 100x better than stackless coroutines, period.

Especially when we have actual threads with UMCG.

Re: Zig's New Async I/O

#276
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…

Does Zig have closures? If yes, than at least in that case the IO pointer can be a bound parameter. For languages with the async keyword function coloring also applied to closures.

Re: Zig's New Async I/O

#277
post #269
post #265

Earlier quoted context omitted.

That's the reason for the thread pool, and the resulting thread affinity issue.

This seems to assume that the same green thread will always run on the same native thread, which I don’t think is universally the case.

Different languages give different level of control over that. There are languages with one main thread pool and perhaps some specialized ones that users don't have control over. Go would be an example of this.

It is also possible for languages to make user creatable thread pools - possibly even with affinity to cores, allowing fibers to run only on a single thread. Crystal is coming along that path. So far it seems to be coming around fairly nicely but I havn't had to battle the GC in anger yet.

Re: Zig's New Async I/O

#278
post #229

Earlier quoted context omitted.

What is wrong with async in JS?

single threaded, memory requirements, function coloring

> single threaded

The entire language is single thread. But I/O uses a separate thread pool.

> memory usage

Are you talking about extra 120 bytes per Promise?

> function coloring

How does it manifest in JS? You can `await` non-async function without any issues, anything potentially async is awaited, if it doesn't end up doing async inside there is no problem.

Re: Zig's New Async I/O

#279
The discussion around function color misses the distinction between the typical await approach and other solutions.

For example, consider a library that implements the C preprocessor; it implements a single function that takes a string to be processed and applies the C pre-processing algorithm to it and returns the preprocessed string.

     c_preprocessor_v1(body: string) -> string
The C preprocessor has includes operations, so it might need to (recursively) open additional files. Instead of making assumptions about what's the include path is or even the existence of a filesystem, the designer of the c_preprocessor decided, in v2, to delegates the file opening to a separate function [1]:

     c_preprocessor_v2(file: path, loader : path->string) -> string
c_preprocessor_v2 will incrementally call loader as it discover new include statements, possibly from the output of loader itself.

_v1 can of course be implemented in term of _v2 given a default loader definition.

Now you want to implement a preprocessor-as-a-service. It provides a rich API for the user to submit an initial file to your service and for the service to ask the user to submit the additional files on demand. And of course you want to use the c_preprocessor library. You expect your service to have to server hundreds of thousands of concurrent requests, so you want to make it async, in particular you want to make the loading async.

If you are using JS I believe you are screwed: you can't use the library as is: c_preprocessor_v2 and the async loader live in separate worlds: red (async) functions can call blue (sync) functions, but not vice versa; you need to ask the maintainer for a new async c_preprocessor_v3 that takes an async loader.

In some other languages (rust, c#, python) can wrap your async loader with a wrapper that blocks (in a way, closing over the async-ness of the function), but this is hardly ideal, the resulting call to c_preprocessor_v2 would not be async and prevent you from scaling to hundreds of thousands of requests. You might play around with offloading to thread pools, but as the bulk of the work is inside the c_preprocessor function it is never going to work well. In practice your blue functions can call red functions, but the resulting function is blue.

There is a third class of languages that allow you to combine blue and red functions producing red ones (Go, lua, scheme, and I believe this new Zig proposal); in these languages the caller can sandwich calls to sync functions across async domains, while still allowing suspending the whole call stack.

One disadvantage of the third class is that, as side effects are often unrestricted, if c_preprocessor relies on hidden global state, it might not be able to handle reentrancy correctly.

There is then a fourth class of languages where, not only side effects are always explicit (Haskel, some effectful programming languages), it is possible, and indeed idiomatic to be able to abstract over it. So c_processor_v2 might not only be able to call synchronous or asynchronous loaders transparently, but the idiomatic implementation might even be able to extract additional concurrency by not imposing dependencies unless necessary. One interpretation is that in these languages functions are always red, but I think that's reductive and not useful.

[1] this example uses higher order functions, but an OOP example would be of course completely equivalent.

Re: Zig's New Async I/O

#280

Earlier quoted context omitted.

This is like saying arithmetic is a form of calculus, the simplest form. Ie it reduces the concept (DI) to a meaningless tautology.

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) but it certainly means that all the people discussing DI (like yourself) are peddling snake oil...?

[1] https://en.wikipedia.org/wiki/Dependency_injection

Post reply on HN