Live data from Hacker News

How I turned Zig into my favorite language to write network programs in

lalinsky.com

101–110 of 150 posts

Re: How I turned Zig into my favorite language to write network programs in

#101
post #67

Earlier quoted context omitted.

> Not all GCs are born alike. True. However in the bounded-time GC space few projects share the same definitions of low-latency or real-time. So you have to find a language that meets all of your other desiderata and provides a GC that meets your timing requirements. Perc looks interesting, Metronome made similar promises about sub-ms latency. But I'd have to get over my JVM runtime phobia.

I consider one where human lifes depend on it, for good or worse depending on the side, real time enough.

Human lives often depend on processes that can afford to be quite slow. You can have a real time system requiring only sub-hour latency; the "realness" of a real-time deadline is quite distinct from the duration of that deadline.

Re: How I turned Zig into my favorite language to write network programs in

#102
post #54

Earlier quoted context omitted.

Go has tricks that you can't replicate elsewhere, things like infinitely growable stacks, that's only possible thanks to the garbage collector. But I did enjoy working on this, I'm continually impressed with Zig for how nice high-level looking APIs are possible in such a low-level language.

Also, it is about time to let go with GC-phobia. https://www.withsecure.com/en/solutions/innovative-security-... https://www.ptc.com/en/products/developer-tools/perc Note the > This video illustrates the use case of Perc within the Aegis Combat System, a digital command and control system capable of identifying and tracking incoming threats and providing the war fighter with a solution to address threats. Aegis, deve…

Real-time GCs can only guarantee a certain number of deallocations per second. Even with a very well-designed GC, there's no free lunch. A system which manages its memory explicitly will not need to risk overloading its GC.

Re: How I turned Zig into my favorite language to write network programs in

#103

Stackful coroutines make sense when you have the RAM for it. I've been using Zig for embedded (ARM Cortex-M4, 256KB RAM) mainly for memory safety with C interop. The explicitness around calling conventions catches ABI mismatches at compile-time instead of runtime crashes. I actually prefer colored async (like Rust) over this approach. The "illusion of synchronous code" feels magical, but magic becomes a gotcha in lar…

The new Zig IO will essentially be colored, but in a nicer way than Rust.

You don't have to color your function based on whether you're supposed to use in in an async or sync manner. But it will essentially be colored based on whether it does I/O or not (the function takes IO interface as argument). Which is actually important information to "color" a function with.

Whether you're doing async or sync I/O will be colored at the place where you call an IO function. Which IMO is the correct way to do it. If you call with "async" it's nonblocking, if you call without it, it's blocking. Very explicit, but not in a way that forces you to write a blocking and async version of all IO functions.

The Zio readme says it will be an implementation of Zig IO interface when it's released.

I guess you can then choose if you want explicit async (use Zig stdlib IO functions) or implicit async (Zio), and I suppose you can mix them.

> Stackful coroutines make sense when you have the RAM for it.

So I've been thinking a bit about this. Why should stackful coroutines require more RAM? Partly because when you set up the coroutine you don't know how big the stack needs to be, right? So you need to use a safe upper bound. While stackless will only set up the memory you need to yield the coroutine. But Zig has a goal of having a built-in to calculate the required stack size for calling a function. Something it should be able to do (when you don't have recursion and don't call external C code), since Zig compiles everything in one compilation unit.

Zig devs are working on stackless coroutines as well. But I wonder if some of the benefits goes away if you can allocate exactly the amount of stack a stackful coroutine needs to run and nothing more.

Re: How I turned Zig into my favorite language to write network programs in

#104
post #103

Stackful coroutines make sense when you have the RAM for it. I've been using Zig for embedded (ARM Cortex-M4, 256KB RAM) mainly for memory safety with C interop. The explicitness around calling conventions catches ABI mismatches at compile-time instead of runtime crashes. I actually prefer colored async (like Rust) over this approach. The "illusion of synchronous code" feels magical, but magic becomes a gotcha in lar…

The new Zig IO will essentially be colored, but in a nicer way than Rust. You don't have to color your function based on whether you're supposed to use in in an async or sync manner. But it will essentially be colored based on whether it does I/O or not (the function takes IO interface as argument). Which is actually important information to "color" a function with. Whether you're doing async or sync I/O will be colo…

This is not true. Imagine code like this:

    const n = try reader.interface.readVec(&data);
Can you guess if it's going to do blocking or non-blocking I/O read?

The io parameter is not really "coloring", as defined by the async/await debate, because you can have code that is completely unaware of any async I/O, pass it std.Io.Reader and it will just work, blocking or non-blocking, it makes no difference. Heck, you even even wrap this into C callbacks and use something like hiredis with async I/O.

Stackful coroutines need more memory, because you need to pre-allocate large enough stack for the entire lifetime. With stackless coroutines, you only need the current state, but with the disadvantage that you need frequent allocations.

Re: How I turned Zig into my favorite language to write network programs in

#105
post #103

Stackful coroutines make sense when you have the RAM for it. I've been using Zig for embedded (ARM Cortex-M4, 256KB RAM) mainly for memory safety with C interop. The explicitness around calling conventions catches ABI mismatches at compile-time instead of runtime crashes. I actually prefer colored async (like Rust) over this approach. The "illusion of synchronous code" feels magical, but magic becomes a gotcha in lar…

The new Zig IO will essentially be colored, but in a nicer way than Rust. You don't have to color your function based on whether you're supposed to use in in an async or sync manner. But it will essentially be colored based on whether it does I/O or not (the function takes IO interface as argument). Which is actually important information to "color" a function with. Whether you're doing async or sync I/O will be colo…

> You don't have to color your function based on whether you're supposed to use in in an async or sync manner. But it will essentially be colored based on whether it does I/O or not (the function takes IO interface as argument). Which is actually important information to "color" a function with.'

The Rust folks are working on a general effect system, including potentially an 'IO' effect. Being able to abstract out the difference between 'sync' and 'async' code is a key motivation of this.

Re: How I turned Zig into my favorite language to write network programs in

#106
post #31

Earlier quoted context omitted.

Pre-1.0 Rust used to have infinitely growing stacks, but they abandoned it due to (among other things) performance reasons (IIRC the stacks were not collected with Rust's GC[1], but rather on return; the deepest function calls may happen in tight loops, and if you are allocating and freeing the stack in a tight loop, oops!) 1: Yes, pre-1.0 Rust had a garbage collector.

Rust still has garbage collection if you use Arc and Rc. Not a garbage collector but this type of garbage collection.

You mean Drop, which is entirely predictable and controlled by the user?

Re: How I turned Zig into my favorite language to write network programs in

#107
post #40
post #30

I am still mystified as to why callback-based async seems to have become the standard. What this and e.g. libtask[1] do seems so much cleaner to me. The Rust folks adopted async with callbacks, and they were essentially starting from scratch so had no need to do it that way, and they are smarter than I (both individually and collectively) so I'm sure they have a reason; I just don't know what it is. 1: https://swtch.…

I think it started with an interrupt. And less abstraction often wins.

This is the only explanation here I can intuitively understand!

Re: How I turned Zig into my favorite language to write network programs in

#108
post #54

Earlier quoted context omitted.

Go has tricks that you can't replicate elsewhere, things like infinitely growable stacks, that's only possible thanks to the garbage collector. But I did enjoy working on this, I'm continually impressed with Zig for how nice high-level looking APIs are possible in such a low-level language.

Also, it is about time to let go with GC-phobia. https://www.withsecure.com/en/solutions/innovative-security-... https://www.ptc.com/en/products/developer-tools/perc Note the > This video illustrates the use case of Perc within the Aegis Combat System, a digital command and control system capable of identifying and tracking incoming threats and providing the war fighter with a solution to address threats. Aegis, deve…

That GC introduces latencies of ~1000µs. The article is about eliminating ~10µs context switching latencies. Completely different performance class. The "GC-phobia" is warranted if you care about software performance, throughput, and scalability.

DoD uses languages like Java in applications where raw throughput and low-latency is not critical to success. A lot of what AEGIS does is not particularly performance sensitive.

Re: How I turned Zig into my favorite language to write network programs in

#109

Stackful coroutines make sense when you have the RAM for it. I've been using Zig for embedded (ARM Cortex-M4, 256KB RAM) mainly for memory safety with C interop. The explicitness around calling conventions catches ABI mismatches at compile-time instead of runtime crashes. I actually prefer colored async (like Rust) over this approach. The "illusion of synchronous code" feels magical, but magic becomes a gotcha in lar…

All synchronous code is an illusion created in software, as is the very notion of "blocking". The CPU doesn't block for IO. An OS thread is a (scheduled) "stackful coroutine" implemented in the OS that gives the illusion of blocking where there is none.

The only problem is that the OS implements that illusion in a way that's rather costly, allowing only a relatively small number of threads (typically, you have no more than a few thousand frequently-active OS threads), while languages, which know more about how they use the stack, can offer the same illusion in a way that scales to a higher number of concurrent operations. But there's really no more magic in how a language implements this than in how the OS implements it, and no more illusion. They are both a mostly similar implementation of the same illusion. "Blocking" is always a software abstraction over machine operations that don't actually block.

The only question is how important is it for software to distinguish the use of the same software abstraction between the OS and the language's implementation.

Re: How I turned Zig into my favorite language to write network programs in

#110
post #56

Earlier quoted context omitted.

following upstream is overrated since we have good package managers and version control. it's completely feasible to stick to something that works for you, and only update/port/rewrite when it makes sense. what matters is the overall cost.

Hmm, if one writes a library Zetalib for the language Frob v0.14 and then Frob v0.15 introduces breaking changes that everyone else is going to adapt to, then well, package managers and version control is going to help indeed - they will help in staying in a void as no one will use Zetalib anymore because of the older Frob.

For libs, yes, for applications dev, no.

I would expect fixing an application to an older version would be just fine, so long as you don't need newer language features. If newer language features are a requirement, I would expect that would drive refactoring or selecting a different implementation language entirely if refactoring would prove to be too onerous.

Post reply on HN