Not sure if I understand what you mean.
To fix my problem, I would then add a localAddress option to connect. But that’s only fixing the symptom. The real fix would be to split creating the socket and connecting. But that’s affecting all std.Io implementations structurally. There are a couple more options, all of them breaking changes.
How likely is it that the guy working on std.Io would accept the PR as is or even look at it any time soon?
I don’t think this is the right approach. Something as important as the abstraction over a cross platform abstraction over all OS functionality affected by IO and concurrency should not be driven by fixes of random users hitting a wall.
What should be done here in the concrete case is to not merge multiple API steps into a single operation if the operation only supports a subset of what the OS supports. There was a reason for this decision and likely a good one. They guy who made the decision knows and this guy should drive the design. Whatever I would do ignores the reason for why it was done otherwise.
It’s not that I’m too lazy to contribute, I just don’t believe that this kind of thing is what should be driven by me or people in my situation.
I came across this problem in the past. I don’t remember the details, but it was related to reading file attrs with stat. The std implementation did not deliver the complete set of data from the syscal (or something similar) and as a consequence, I had to revert to direct syscall interface. The reasoning behind it was that std wants to be platform agnostic or work cross platform and thus cannot support all OS fully.
This argument certainly makes sense in the context in which it was made, but the approach of the lowest common denominator is not a universal solution, it’s only convenient. There must be a path to access the guts of a system if the use case needs it. This is always there in the absence of abstractions like std.Io. You can always call out to linux/win/… But with abstractions that maintain their own state and make their own assumptions about it (a socket must be blocking, …) that are not innate to the interface but the implementation, this escape hatch disappears. The error handling is an example for that, where two contracts conflict (linux semantics of non-blocking connect and std.Io abstraction contract).
std.Io must be designed to be convenient (that’s the whole point of it) but it must also be correct and complete. I don’t believe it can be both without a coherent design with these goals in mind. My PR would fix my problem or maybe the issue with socket create/connect but not all the other issues that might be lurking around the corner. But my PR would be breaking code if accepted. And the next PR would too.
I probably sound like the typical whiner who complains and doesn’t want to contribute. What I try to say is that std.Io should not grow organically. And it’s too big to be hacked together in a week or too. It’s also too important to be unfinished, because there is no adopting std.Io a bit and using other things in parallel, because std.Io when adopted becomes the architecture baseline of whatever is using it.
Arguing from my personal perspective, patching up std.Io doesn’t solve my problems, because that only adds one more layer of vendored dependencies and makes it harder for the others I have to stack on top of them, in this concrete example I would change std.Io signatures, then ask zio to use the speculative new structure, then ask httpx to also use it. I don’t think that is productive for me. I could try to become a core member of Zig, and I would love to, but that’s also not solving my concrete problems to bind to a local address or read file attributes, etc.
I believe I understand your perspective and I don’t think mine should override yours, I just want to make sure you see mine too ![]()