I had to reflect on this, but, yes, I do agree with that. A function/module should do networking or file I/O but not try to abstract over both.
The baseline hardware characteristics are just vastly different. File I/O, by and large, is fairly reliable, low latency, high bandwidth, and randomly seekable. Network I/O is terribly unreliable, widely varying latency, low bandwidth (although not always), and generally not randomly seekable.
That variance leaks through into the programming abstraction. For example, the error profiles are vastly different. File I/O generally has a bounded set of failure conditions that are probably enumerable with reasonably bounded upper latency that you can generally handle in your code. Network I/O has an almost unbounded set of failure conditions (certainly not enumerable) only a small number of which you could possibly do anything about in your program (what could or even should your code do when DNS is dead or crypto isnāt available?) with latency whose upper bound is infinity.
If you try to abstract over both, you wind up with a stunted set of primitives that only sorta work and always cut people with a rough edge. Everybody always quotes āEverything in Unix is just a file!ā but even the Elder Unix Gods⢠had to grapple with the impedance mismatchālook at the weird mishmashes of ioctl and fnctl in Unix system programming (everybody has forgotten that ābaudā and āparityā used to drive people to violence). Another good example of this kind of programming issue is a general āStringā typeāevery String type always has a slight impedance match with the problem you are working on and eventually everybody has to roll their own. Itās better to simply accept that File and Network (and Deviceāthings like USB devices and GPUs and ā¦) need a rich programming API and those APIs are quite different from one another.
Although, to be fair, I think the discussion is probably orthogonal to the the real problem. I suspect the real issue is how to make a good programming abstraction for āconcurrency notificationā and subsequent control transfers The problem is that concurrency notification (and maybe concurrency in general) is at a very messy intersection of software/hardware, runtime/comptime, operating system/programming language, active run/passive wait, priority/fairness, interrupt/polling, etc.
Up to this point, only the managed memory languages seem to have ⦠I wouldnāt say good but at least maybe ānot terribleā ⦠programming abstractions around concurrent operations. Iām looking forward to seeing if what Zig put on the table eventually proves itself as something novel and useful.