CL OS Approach

cosc19z5@bayou.uh.edu cosc19z5@bayou.uh.edu
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 
before.

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
functions.

Data files will be symbols.

The entire hierarchal file system should appear as a hierarchal
module.

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.
;;
> (objects) 
(#'emacs
 #'gcc
 makefile)
 

;; To see a list of objects in a submodule, we pass the module
;; of interest as a symbol (equivalent to listing files in another
;; directory).
;;
> (objects 'usr:bin:games)
(#'chess
 #'zork
 #'nettrek
 readme)


;; To run an executable, we merely call it as a function.
;;
> (chess)
...


;; 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:
;;
> (usr:bin:games:chess)


;; 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.
;;
> readme
...


;; Again to disambiguate, we can do:
;;
> usr:bin:games:readme


;; 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
(ideally) be.

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 
programmable environment.

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
		possible.

	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)
should be:
	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
		metaphor. 

	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.

Regards,
Ahmed