Quick, everyone sh*t on Io!

Well hello there. I am not going to make another thread to do that. It was just bait to get everyone’s attention. It seems everyone has a stance on Io. I’m gonna start by saying that seeing embedded people cry about a vtable, when if you look into any standard bootstrap for any microcontroller on the planet you see an interrupt descriptor table (which has 256 of them, BOO!), is honestly a bit disappointing. I think, stances like “Run! A vtable! We were taught to hate those!” lack critical thinking. While I will not diminish the benefit that compile time polymorphism provides, interfaces are a standard part of any … well … interface. All the better that Zig is so explicit in their formulation, it forces restraint. Said that, I question what precedent does this set in the design of user applications. The standard library is the holy grail of any language, at least from the perspective of many newcomers, and the usual way to learn idiomatic approaches is to look at the standard library.

Looking at the os level hackers having an issue with it is even more laughable, because how are you going to say that a constant dispatch table adds overhead to a system when you have dynlib calls and kernel syscalls on the other end of them. The icache is a thing, it’s much more important what’s in it than whether it’s comptime known, this is not 2016 and we are not the standards comittee.

Now that everyone is properly in their place and pissed off, here is my story time:

I wake up, update my zig, start migrating to all the shiny new io interfaces (which I shoulda done a long time ago anyways). Okay, reasons, reasons, …; cross compatibility, centralized, extensible, hotswap your implementations during runtime, deterministic, testing, simulations, The Matrix, Martha Steward, whatever, think of the reasons… Ooooookay. I get to a part of the code that uses a kernel32 API call, and it’s… not there?!

THIS IS OUTRAGEOUS!

Here is the actual message:

I can see why migrating higher level library APIs to use NTDLL would be of interest to the team, I love that there is a non-libc linux implementation for everything imaginable, but for the love of me I can not possibly understand about why a systems level programming language that had a mature and perfectly working native wrappers around system interfaces removed bindings. It’s like, here is all the work we have put into building this lower level APIs to allow people to interact with standardized OS-level stuff, nobody on the market except the original vendors has or even attempts this, it’s already finished, but we will remove it. It’s, and I say it as humbly as I can, a bad move. In the words of a great poet: “I will use your Io, please don’t take away my posix!”.

On the other side of that argument is, well, if we want to keep the library lean and mean, we should probably only keep the lower level abstraction layers that it actually needs, and I can perfectly see that reasoning, I just really dislike the outcome. Unless I am missing something with compilation times, that stuff should have stayed. Posix targets without libc? Eh? Is that even a thing? I don’t know? But they are not synonymous, so I presume there is some merit to keeping them separate, again, not enough information on my part to see if that’s an appropriate decision. Unless there is some replacement for the posix interfaces it’s again a miss.

That said, the bindings are still in the tree, nobody is forcing you to leave them erased *wink wink* and I think “selling” Io to disbelievers could be much easier if it wasn’t followed immediately by “oh btw, the rest? it’s all gone”. I don’t think the feedback is a bad thing, I think it’s great to see a community so invested into a piece of technology that it really worries them when it is taking a turn they do not see as positive. I think a self hosted compiler is amazing, what you have done around the build system and the language is absolutely phenomenal, and I have my greatest hopes that we are in the end going to end up in the right place. I also hope you will resist the evil temptations of *spits in disgust* Rustaciean script-kiddies, who want to turn everything and their mothers into a language feature, will iterate fast and hard, keep it lean and mean, not fear God nor failure, pivot when you see you made a bad move, and continue building on a trajectory so phenomenally engineer.

I’m going to be mad if you don’t take back the kernel32 bindings, I’m going to make this thread, but that’s as much as I’m going to do about it; Please figure out how to approach this, give it some more thought, keep being awe-sauce, don’t give up on your dreams.

I want to send all my warmest regards to Andrew, the team, and everyone working hard on making this the best software project I’ve seen since Linux and/or hand-writing assembly instructions with a sharpie on a piece of hanckerchief in a cigarette-smoke filled train coupé.

6 Likes

you are not alone

new Io related issues were discussed e.g.

https://ziggit.dev/t/should-the-standard-library-be-batteries-included/ (second part)
https://ziggit.dev/t/what-i-learned-about-bun-zig/

I solved similar problem using Zig as best C and complete rewrote low level of my network project using C binding

Let’s wait, zig is just 0.16.0

It will take time to understand cost of improvements …

To make sure we’re on the same page, are you aware of this:

Also, if you haven’t seen them, here’s a few relevant links:

10 Likes

What I am more annoyed by is that there is no low level unified interface over different operating systems right now (unlike the high-level std.Io interface).

Yes, Andrew Kelly said that there is std.Io.Threaded.*, but by far most of it is actually private. So that doesn’t work.

And the alternative is right now to write code for each OS individually.

1 Like

You need to give time to the stdlib to progress. The old layer was morphed into being the lower layer for std.Io, making it unsuitable for direct usage. A new lower layer needs to re-emerge, but it will take some time, and the higher priority is to get the Io stuff right.

This is not particularly different than when things have broken in the past. Be patient, use workarounds in the meantime, and be ready to participate to the development discussion when the time comes if you’re opinionated on this stuff.

17 Likes

I think kinda opposite. I like this new direction because it is not bunch of switches against immutable set of operating systems, but rather there is now proper interface that you can implement even outside. It is not also pretending to be a posix and ignoring the fact some posix functions can’t even be implemented on some systems, or they have to be implemented very poorly. This allows lots of interesting use cases and is more welcoming for freestanding / custom operating systems. (There are still some problems for freestanding use case like (https://codeberg.org/ziglang/zig/pulls/31235), but things are improving as is the Io interface and its implementations).

And yes, I do use both std.Io and OS specific functions.

11 Likes

I mean such a low level API more as something you can use to build something like std.Io on top yourself.

For example if the stackless coroutine proposal actually gets implemented, one might want to do this for std.Io (just outside of the stdlib) and use the low level API for stuff which either isn’t doable or on the todo list.

2 Likes

Yeah, I don’t disagree there. Some functions in std.Threaded are pub. But as @kristoff mentioned it is unclear what the actual lower level interface will be. Interaction with async/coroutines/stackless is also bit chicken-egg problem as it’s heavily tied to the Io implementation. Evented on linux for example uses io_uring, and it requires that all IO is also done through io_uring.

Whats the alternative? epoll? Is there any reason to it outside of security holes? It’s been around since 2019 and if tigerbeetle is using it… Though a epoll implementation could for sure come once the primary evented one is finished.

Even with epoll the problem would be the same. I’m saying that for Evented, the heart and soul is the single OS primitive that provides the API for performing a IO operation, waiting for it and canceling them. For Threaded, the heart and soul is OS threading primitives, and this is arguably the most portable way to do it, but won’t let you cancel operations mid-flight.

This feels like oxymoron to me. The low-level (systems) interface must losslessly expose the underlying OS, so it can’t be unified by definition. Unification gives you something IO-shaped.

19 Likes

It will be an iterative process - Io does not use any magic APIs, it uses what the host OS supports

With the growing maturity of Io, it will become clearer which low-level “blocks” may be used in “autonomous” mode

I expect some split of Io -

  • Io itself as a high-level abstraction
  • low-level blocks/bricks/API for special software

I’m waiting for Zig 0.20.0

1 Like

the “intermediate” or oxymoronic (lol) nature of old std.posix is probably why a lot of people hated it

1 Like

well, there is one around threads (std.Thread)

and that’s pretty much what I mean here