8 ms·
I think a bigger problem is that a pseudo-file is not actually an especially good API for any use case. It's a sort of compromise solution that makes nobody hap
by origin_path 4y ago
I think a bigger problem is that a pseudo-file is not actually an especially good API for any use case. It's a sort of compromise solution that makes nobody happy. The sockets example is a good example. What programmers want is a function or OOP style API where they can pass strings, type safe structures and so on, but a file is just a stream of bytes so they invented some ad-hoc socket-opening-protocol thing, presumably so you can shell script it. But then shell scripts want to use higher level protocols so it's not useful for them, and programs would wrap that pseudo-file with a library API anyway, so it's just an implementation detail and not so great for that job either. Like, it can introduce a world of parsing/escaping/versioning bugs, race conditions and overheads.
In contrast a custom syscall that takes a structure is a more direct interface, more suited for writing actual programs.
It also means the API is much more tightly defined. Everything-is-a-file can create a lot of edge cases just like how HTTP creates a lot of edge cases in web programming by pretending everything is a document. What happens if you delete /dev/draw, what does that mean? You need to define the semantics of that. Does it mean closing the window? What about trying to move or copy it - does that make sense? Do you have time to think about all these operations and give them meaningful results?
Once you go down the road of saying that there should be a consistent set of operations you can perform on conceptual 'objects' using a generic set of tools and commands, you may start to wonder why you'd pick a file API for that. Why not just invest in objects as a core tech - why not allow binding directly to an object in a remote process or over the network and then have methods and functions actually work? Why pretend it's a file and force everyone to constantly invent mini-protocols and formats, when types and functions are what you need 90% of the time anyway? That's why Microsoft ended up going down the DCOM path, why Apple ended up with XPC/Mach, why Android/BeOS ended up with the Binder and so on. The Plan9 approach wasn't taken up in any big way because if you're going to make a big effort to unify everything it might as well be around objects, not files.
- zozbot234 4y agoA pseudo file works just fine as a low-level API/ABI, that you could layer higher level interfaces on top of. What does it mean to delete/move/copy etc. a pseudo-file? That's going to vary. The operation might simply be disabled and return a generic error. AIUI, generalized OOP interfaces end up having the same issue to an even greater extent.
- origin_path 4y agoOOP interfaces as the core concept have several advantages over a pseudo-file based system, even if you assume a higher level RPC system that uses files under the hood: 1. OOP can at least in principle abstract over whether code is in-process or in a remote process, with efficient stack based calls for in-process calls and serialization/RPC for remote calls. Yes you can't make them be identical, but you can bring them very close together. But files are fundamentally a kernel controlled object. For a pseudo-file system to hold together at all, you end up having to talk to the kernel all the time, which is slow (ish). 2. OOP has the notion of a queryable set of interfaces. UNIX style file objects don't have any equivalent, which is why you suggest that operations that don't seem to make sense should just return a generic error code. But this is bad. If we saw a junior programmer both design and then implement an interface in which most methods returned error codes we would school them (it can of course be acceptable if you don't control that interface but even then, really not ideal). A much better approach is to define interfaces better so that your objects only implement operations that make sense, and a generic client can use type casting / IUnknown::QueryInterface style operations to figure out what an object can do. 3. Just as you can't opt-out of generic file operations, you also can't add more. That's why you end up having this split world in which some toy operations are just basic file IO and then the moment you need anything complex enough for the real world, your file becomes just a sockety thing speaking some ad-hoc protocol and you can't use the file directly anymore, e.g. you can't shell script it, you need some ad-hoc library that wraps it. There are tons of files in /dev but how often do you see code that directly uses them? Almost never - apps use libraries that wrap the file interface. 4. The lack of proper interfaces and type safety means that evolving stuff is way too hard. Doesn't matter for a research OS but matters in reality. Look at the docs for /dev/draw, it's all ad-hoc protocols with no proper versioning or evolvability at all, just stuff like "open the device and read 12 strings each 11 characters wide" (!). I think that even though they suffer from execution issues, Microsoft was heading down the right path with COM and PowerShell. COM provides you with objects, which is way more commonly what you actually want. DCOM attempts to abstract over location, so the serialization and sockety/filey stuff only gets involved when necessary. And PowerShell attempts to give you a shell-like syntax for accessing them. For various reasons it doesn't quite work as well as it could, hence why concepts like Plan9 have enduring fascination, but the core ideas are more general and robust.