I’m looking for papers and projects related to building a general purpose operating system using Ada. I see there are some that already exist such as Ironclad and CuBit.
I’m also interested to hear if anyone has ideas about what a general purpose Ada OS would look like.
For a historical account, there’s some documentation on the “Army Secure Operating System”, which as I understand is an OS written in Ada.
As for what an OS written entirely in [modern] Ada, with (a) an eye toward portability, and (b) eschewing the design disasters that are Unix/C/POSIX, the way I’d do it is thus:
The entire OS would be constructed with types; the fundamental types having a metaobject system with ASN.1 (ie you get ASN.1 serialization “for free” across all types in the system) streaming.
First-class support for (a) generics [shared], (b) tasks, and (c) a system ‘Collections’ built off of the attributes/aspects Guy Steele talks about in the tail end of his “How to think about parallel programing, not.” presentation [that is, geared toward parallelism and the “algebraic properties” he mentions].
A UI system that is like Delphi’s VCL, but able to be “rendered” in Text (ala TVision) or video-mode; this would make the utilities able to be used in a variety of situations, even where the capabilities are very restricted.
(This has happened to me a couple of times where the utility I needed to use wasn’t accessible in the modes that were available to me; another, related, issue is user input: sometimes your utility is to e.g. get the mouse or keyboard working, but you need that to use the utility. Also frustrating; therefore good keyboard accelerators, as well as mouse/virtual-keyboard support, should be critical for this “TVision VCL mode”)
Rejection of the “text-first” mentality of Command-line/grown-from-REPL methodologies.
For example, parameters should be passed in as a stream of typed objects;
Parameter parsing should be done by the OS (thus you do not force ad hoc parsing)
Output, similarly, is a stream of typed objects, thus the notion of “piping together programs” does not discard type information.
Taken together, you avoid the “oh, the program’s output gave me an unexpected zero/negative-number/whitespace and that caused my program to behave badly/crash” of Unix-style forced ad hoc parsing.
A database (rather than filesystem) oriented storage methodology; this allows for structures [of the would-be binary-file formats] to be accessible as DB items.
The unification of the idea of type and “DOMAIN” (and subtype and “CHECKED DOMAIN”), record and “ROW”, instantiation of Ada.Containers.Indefinite_Vector (with record) and “TABLE”; allowing the metaobject system to incorporate/implement notions of the database of SQL.
Having a “Verified Unification Engine” which drives both the SMT prover and database engine, thus allowing the OS to provide SPARK-like services as well as DB-services.
It’s all interesting idea but how would an interface go about this? Are we still using text? E.g. passing arguments to a program like tar -c bla boo bing | gzip > bla.tar.gz
I’m also not sure what benefit the OS has in terms of kernel space to parse arguments. Or do you mean OS as in some kind of fundamental interactive shell? The program dictates the argument format and therefore would need to figure out if the arguments are acceptable. Perhaps it could present a list of acceptable types the OS/shell/wherever can check and refuse to exec the program if the arguments don’t match.
Why would text be needed for this?
The Command-line Interpreter would parse this, and everything else uniformly.
Instead of receiving strings/pointers-to-strings the main would interface with the environment by a stream, the same for output.
Now, having a text-renderable stream (ie the invocation & parameters) may impose restrictions on the form to aid parsing. Given your specific example, perhaps the parameters would be (“c” => FILE_HANDLE(“bla”), “” => [FILE_HANDLE(“boo”), FILE_HANDLE(“bing”)]) for the first program, and for the second (“output” => FILE_HANDLE(“bla.tar.gz”))
… the main point here is that you work inside-out compared to how we do things currently: the parameter-stream is a typed object-stream, properly formed and formatted, “before the program ever smells it”. (e.g.) Something like dir (or ls) doesn’t return a blob of text, but rather a proper collection of file-objects, displaying them as directed… or passing them on through the parameter-stream.
Thus, “OS-wise” we get a system where even UI can be seamlessly interchanged. (ie TUI vs GUI handling becomes more uniform; the “rendering” becomes more amiable to MVC-style rendering “text” or “UI” as a mere “view”.)
That’s the job of the UI/command-interpreter.
I hate JSON, but that is kinda the idea here: it’s not prog some text that is unstructured, but prog {parameter_1 => value_1, parameter_2 => (value_3, value_4), parameter_3 => value_5} for whatever structured textual representation is chosen. The program can have some structure/DTD showing what it accepts and validation thereof.
(DTD: Data Type Definition; XML used a DTD file to allow XML to be validated against types/constraints.)
The main issue I see with such a system is pace of development/progress. If you update and re-compile everything together it might work. But suppose you want to update one of your main data types like FILE_HANDLE in an incompatible way. Suddenly half of the programs cannot talk to each other anymore.
Or suppose you have program A, that is able to process/transform UTF-8 text in a certain way, so it has an UTF-8 input and output. Suppose program B can only handle ASCII for whatever reason. This means you cannot pipe an ASCII file through A to B even if you know that the output of A in that case is only ASCII.
Strong typing is fine for tightly coupled systems, like embedded and I love Ada in that domain. But for large loosely coupled systems (and large systems need to be loosely coupled to be able to handle the complexity), it easily gets in your way.
To to put it the other way round: Programs/systems written in strongly typed language have the tendency to become strongly coupled if you don’t actively avoid it.
That is why it should be an OO type system. Along with multiple inheritance which Ada supports only partially it also must have ad-hoc supertypes which Ada does not have. With these you could add a virtual ancestor to two existing independent hierarchies.
Ah, BTW in a modern OS there would be no files, only persistent objects.
I do not see how it is related to the strength or absence of typing. If your FILE_HANDLE changes from 32-bit index in descriptor table to 64-bit flat address in the kernel space, then how an ability to pass a random character string for it would help?
PowerShell does it the retarded-way-around.
Instead of being object-first, it’s more “object bolted on”; you can tell this by the way that there’s no uniformity to “methods” on the objects and (even more damning) no “object viewer” like [IIRC] Smalltalk had. — So, while “yes” PowerShell “does it”, it’s more like type-annotations on PHP rather than types-in-Ada.
The idea is as old as the 64-bit address space and OO. I wrote on the subject 30 years ago.
The sad thing is that it coincided with the beginning of the Dark Age of Computing when the unholy trinity Windows-UNIX-Intel stopped any progress in all fields. The old ideas were regurgitated as the resources extensively grown. Now we seem to be hitting the wall while on the acceleration booster of the AI hype gobbling everything what left. Interesting times have come…
Ignoring some older, more advanced operating systems, in a modern OS a file is a named bucket of bytes. Object is an opaque container with operations defined on it. You can do nothing with it if there is no operation for that, e.g. you cannot execute a text or print volume. That is yet typed only. It becomes OO when the type system supports sets of types (classes) and objects of sharing same operations. Of course all OSes are inherently OO. Even in UNIX you have classes of devices like block device or terminal device or pipe. It is just so that the OO nature never gets exposed in the API.
This is the essential gist of it; but you can conceptualize “persistent objects” as items that don’t disappear (eg) between runs of a program. So, imagine a program where you have a record of (ID => 7, Name => "Steve", Permissions => (Read => True, Write|Execute => False)), the program finishes running but when you re-run the program the same “Steve” already exists (precisely because you never deleted him).
Another way to conceptualize it is as database-entries, where the “object” is some value in the database whether a record or row or “object”.
Though there is the “OOP” method as well, where some systems like Smalltalk load an “image” which is an object/file/state/environment, and all the items in that environment are themselves objects, restored into the environment on-load; in this manner the system could be radically modified (because it was objects in the environment) and the ‘restore’ operation would take care of bringing all the “advancements” into being — thus you could (eg) have an “object explorer”, itself an object, and essentially bootstrap the whole system, making that “object explorer” into a debug utility.