CL OS Approach
Tue, 24 Mar 1998 09:30:47 -0600 (CST)
In the spirit of the renewed discussion on this list, I will propose
some ideas about a LispOS. Many of these ideas may have already been
suggested by others, so my apologiesi n advance if I cover any old ground.
Also, I make these suggestions while admitting that I am no expert in
Common Lisp or O/S design, and I have never used a Lisp Machine
Furthermore, some of the terms I use will be inexact, and any code
I include will be more like Lisp psuedocode, so forgive errors in
syntax, names, etc...
Now, on to the good stuff :)
The first step to starting a LispOS is creating a Common Lisp Shell.
This will be much easier to implement at first, and can serve as
a good prototype for concepts for the O/S, and give people
something to use and look at.
The shell's purpose should be to map the entire O/S (resources,
files, directories, etc...) into Common Lisp objects.
The Common Lisp listener should be all that a user needs to
do ALL hir work. Checking files, executing files, creating
files, programming, scripting, etc... should all be executable
within the listener, and EVERYTHING should look like a simple
Common Lisp system, rather than "system" calls.
Here is an example:
Executable files (whether they be shell scripts or binaries created
by compilation) should be directly runnable by calling them as
Data files will be symbols.
The entire hierarchal file system should appear as a hierarchal
Commands like ls, rm, etc... should be renamed to something less
file specific (and sensible) and should return objects. The
pretty printer should be modified to display these objects
in a more human readable format and offer support for pagination.
Remember, that all these guys are lisp objects, and hence have all
the capabilities, uses, and limitations that lisp objects have.
This way, these very same commands can be used directly in other
functions which will use their results.
Common Lisp will be a metaphor for _EVERYTHING_.
As an example of what I'm talking about, here are some
sample sessions (Note that I may get the names of some
functions wrong and the syntax of modules wrong, but I think
my point is clear nonetheless). Descriptions of what is being
done will be in comments (;;). Commands that are typed in will
have a ">" in front of them (this is the prompt), and the
output will be directly beneath, without a prompt.
;; Get a list of the objects in the current module (equivalent to
;; ls in the current directory). Notice how executables appear as
;; functions and data files as symbols.
;; To see a list of objects in a submodule, we pass the module
;; of interest as a symbol (equivalent to listing files in another
> (objects 'usr:bin:games)
;; To run an executable, we merely call it as a function.
;; Sometimes though, we may have an exectuable with the same name as
;; a built in function. When this happens, the built in function
;; gets called, but we can force a call of the executable in question
;; by fully qualifying the call with the module, ie:
;; Since data files are merely symbols, we can simply enter the
;; name by itself, and its value (the contents) will be displayed.
;; We will rely on the pretty printer to paginate and display this in
;; some kind of reasonable format.
;; Again to disambiguate, we can do:
;; Creating a new file is done by interning a new symbol. Now this
;; symbol is part of our object system and will persist so that if we
;; quit and come back, we will find it still there.
> (intern 'bugs_in_chess)
;; To give this symbol a value, we merely use setq as we would with any
;; variable. (editor) calls the editor and returns the text entered
;; by the user, or 'nil if save was not selected.
> (setq bugs_in_chess (editor))
;; To make new executables, we will intern a symbol, then use defun
;; on it. For better editing capabilities we may pass an option to
;; the editor, or simply create it via an editor and then set it as an
;; executable object. Possibly (setq checkers (function checkers))?
> (intern 'checkers
> (defun checkers () (...)
And so on.
Notice how the Lisp system is always in control. It isn't like
the Lisp system provides an interface to the O/S, to the user, the
Lisp system takes care of EVERYTHING. This is the way it should
The user can do everything s/he needs within the Lisp system.
It goes beyond being an O/S, it's more like a persistent complete
The user should NEVER have to leave the listener.
There are snags however. Some of them are:
1) Since this will be initially implemented on top of an
O/S, there will inevitably be conflicts between
our way of doing things, and the OS's way. One
particular issue will be Unix's annoying habit
of being case sensitive. We can get around all
that by using strings or '|| for symbols, but
that takes away from the cleanliness, and IMO
hurts our abstraction. We could try pretending that
the problem doesn't exist and use case insensitivity
(match the first file), since we will eventually
dump Unix anyway. Remember, a high level view of
objects (files) is that they are simply names,
so if they are spelled the same, they are the same.
This maps directly onto the concept of symbols, and
I would like to preserve this concept if at all
2) Having things like editors return their text and then having
the pretty printer display it can be pretty annoying.
One option is to allow suppression of the pretty-printer
so that programs for which this makes sense can use
or avoid it. This will also make it easy for programs
which wish to use their own display formats to do so.
The values returned will still be the same, they will
merely be suppressed. Of course this opens the door
to program output not matching displayed output...
3) Efficiency. If we have programs returning all their output and
assigning them to variables, this could really slow things
down. We might be able to get around this by using
temporary files and simply renaming them to the
interned symbols. One way or another, we will have to
be cautious about this.
Advantages to this approach are:
1) We can develop what appears to the end user to be a full
fledged LispOS with relative ease. Developing this
would consist of finding a pre-existing powerful lisp
system with O/S interface capabilities and
using Lisp's introspection capabilities to modify
the read/eval/print loop to do our bidding.
2) We have a (IMO) better metaphor for persistent storage
than traditional files. Files are now nothing
more than symbols in a particular module, and
reading a file is as easy as evaluating the symbol.
Writing it is as easy as using setq on the
symbol (if the file exists) or interning a new symbol
and using setq on it (if it doesn't).
3) Lisp becomes in control of everything. It is now our
scripting, applications, and command-line language,
and all the benefits that come from using lisp will now
apply to these domains. Code can be developed free
of the compile-link cycle, yet can be run as easily
as a native code program. Programs can be written to
generate code to manipulate the "O/S" or vice versa and
the very "O/S" may be easily altered by third parties.
4) Lisp concepts become O/S concepts, so there's less to learn.
Now, I have not done any work to test out these concepts so there could be
other snags/practicalities that I am not taking into account, and other
issues that I may have forgotten to mention, so please be as critical
as you like.
This should be the first step. The other steps (in order)
1) Developing a decent (ie: not X, or Winblows)
windowing system. Again, this system should have
lisp objects at its heart and should work solely
in terms of these objects.
2) Rewriting certain applications to work in terms of the
Common Lisp metaphor, and eventually rewriting
other applications to take advantage of this
3) Writing a "real" O/S that is friendly to our metaphor.
All comments are welcome. Please don't hesitate to rip holes in
this framework if you really think it's that bad. Any suggestions
for improvements, additions, implementation strategies, misc. comments,
etc... are also greatly welcome.