Object Oriented Shell
Bill Birch
bill at ibmpcug.co.uk
Wed Jan 30 04:33:15 AEST 1991
Bill Birch's Object-Oriented Shell (oosh)
2 November 1990
CONTENTS
1 Introduction
2 Classes and File Structure
3 Execution of Methods
4 Special Methods
4.1 Defining a Class with "defclass"
4.2 Defining a Method with "defmethod"
5 Compound Classes
6 On Replacing "make" with an OO Shell
7 Conclusions
1 Introduction
This shell is an experiment in application of object-oriented
ideas to the UNIX environment. It is a shell which allows the user
to define what commands are appropriate for a particular kind of file.
When using the standard shells, users are expected to remember exactly
which command program to run to for a particular file type. For example
to print a 'C' source program you must type:
$ pr -e5 -n foobar.c | lpr
whereas to print a document you need to type:
$ nroff -mm foobar.mm | qprt -q3
two entirely different strings for the same desired result!
"oosh" uses the suffix of filenames to key into a class tree
which defines the behaviour for all the defined objects. In the above
example, you type the same in both cases:
$ print foobar.c
$ print foobar.mm
I have taken the view that the basic object should be a file in
this environment. The UNIX operating system does not provide support
for OO, thus a file cannot have properties or methods attached to it
unless they are in the file itself, (except the obvious ones).
Therefore, an individual file can only inherit the methods of its
class, and cannot have its own unique methods. However, there is
nothing to prevent classes of objects being defined that are
directories. These "compound" objects can contain methods
and properties as sub-files.
The experimental nature of this prototype has meant an implementation
in Bourne shell. Obviously a compiled version would execute faster,
but would require more programming effort.
The rest of this document introduces the "how it works" of oosh.
It is not a user manual, but a note to fellow programmers.
2 Classes and File Structure
2.1 Classes and Suffixes
In this system, files are objects. All files must have a suffix
as in "/tmp/foo.txt" which has a suffix of "txt". The suffix
denotes the class of the file. All the private data of the file
is stored in the file itself. Objects have no other data (unless
it is a compound object which is a directory).
For every defined class there is an entry in the "oosh/classes"
directory. These entries are soft links (ln -s) to the correct
directory in the class tree. Thus the suffix of a file indirectly
points into the class tree.
2.2 The Class Tree
The class tree consists of a tree of Unix directories, with the
root being "oosh/top". Each directory represents a class, hence its
super-class is the directory "..", and each subclass is a directory
entry. For Example here is a partial "ls -R" of my class tree:
oosh/top:
methods
file # file is a class of objects
oosh/top/file:
ascii # ascii is a type of file
bin # bin is a type of file
oosh/top/file/ascii:
methods
c # c is a type of ascii file
ml # ml is a type of ascii file
txt # txt is a type of ascii file
oosh/top/file/ascii/c:
methods
oosh/top/file/ascii/c/methods:
open
pg
oosh/top/file/ascii/methods:
open
oosh/top/methods:
copy
cut
open
pg
print
defclass
defmethod
Each class directory can contain a subdirectory called "methods" which
contains executable files for operating on objects of that class. The
"top" directory's method directory contains all the default methods
for all objects eg:
copy
cut
open
pg
print
Executable files in a methods directory take the object name
as it's first parameter.
3 Execution of Methods
The execution of a method on an object first involves discovering
the class of that object. Then the class tree is searched to find
a method file to execute. The execution proceeds as follows:
1 Extract the suffix of the file object.
2 Find the soft link in "oosh/classes" which points to the
correct place in the class tree.
3 Change directory to the class's directory in the tree.
4 Look to see if the method required is in the "methods" directory
of this class.
5 IF it is present, THEN
execute the method file, passing the object as a parameter.
ELSE
change to the super class ie "cd .."
UNLESS we are in "top" in which case the method is unknown
so just execute it in the normal UNIX shell.
REPEAT from Step 4
The actual code consists of two Bourne shell programs: "dispatch.sh"
covers steps 1 thru 3 and another, "tryit.sh" which executes steps
4 & 5 and is called recursively. The source code is listed in
appendix A.
In order to provide the user with the familiar "command object"
command line syntax, every defined method is implemented by
a softlink between a file in "oosh/bin" and "dispatch.sh".
For example here is a partial "ls -l" of "oosh/bin":
lrwxrwxrwx copy -> dispatch.sh
lrwxrwxrwx defclass -> dispatch.sh
-rwxr--r-- dispatch.sh
lrwxrwxrwx open -> dispatch.sh
lrwxrwxrwx pg -> dispatch.sh
lrwxrwxrwx print -> dispatch.sh
"dispatch.sh" uses its invoked name as the method specifier. eg
$ open foo.txt
actually executes "dispatch.sh" with $0 set to "open"
4 Special Methods
4.1 Defining a Class with "defclass"
Syntax:
$ defclass <super> <class>
The method "defclass", which is supplied in oosh/top/methods
is supplied with the name of a superclass and the name of the class
to be defined. ie
$ defclass .bin o
defines "o" to be a subclass of "bin".
It performs the following operations :
1 Create a directory called <class> in the <superclass>'s
directory.
2 Create a directory called "methods" in <class>'s own
directory.
3 Create a softlink (ln -s) in "oosh/classes" to the
<class>'s directory in the class tree.
4.2 Defining a Method with "defmethod"
Syntax:
$ defmethod <method name> <class> <executable>
To add a new method to a class requires the following steps
to be executed:
1 Create a softlink in "oosh/bin" between <method name>
and "dispatch.sh". This creates a synonym for the new method
which when invoked from the shell actually calls "dispatch.sh".
2 Copy the <executable> file into the class's "methods"
directory in the class tree.
Example:
$ defmethod .pg exe /usr/bin/nm
5 Compound Objects
In order to provide methods for objects on an individual basis
each object must have a way of storing it's private methods.
One approach is to create a class of objects which consist
of more than one file, all contained within a single directory.
The directory may contain many data and executable files private
to the object. To illustrate this here is a simple example of
a comound class called "cmp". The "cmp" methods are relatively
simple, and are all identical (softlinks can be used):
An example object "tst.cmp" consists of the following files:
./tst.cmp:
methods
slots
./tst.cmp/methods:
pg
./tst.cmp/slots:
f1
f2
f3
f4
The "methods" directory contains various executable files, and
the "slots" directory contains data files.
The execution of a method, simply requires that the method
be available WITHIN the object itself to be executed. ie:
#!/bin/bsh
method=`basename $0`
object=$1
cd $object
if test -x $object/methods/$method
then
$object/methods/$method $object
fi
Note that this behaviour requires no modification to the
rest of "oosh", and affects only objects of the "cmp" class.
6 On Replacing "make" with an OO Shell
Probably the most useful tool for programmers is "make".
"make" has implicit rules that define the behaviour for all
files with a given suffix. In OO terms this is the same as
defining methods that are applicable for all members of a class.
To provide similar functions with an Object-Oriented Shell is
easy. For example to compile a 'C' program with oosh you
could type:
$ build fubar.o
The method "build" for ".o" files would then execute the following
just like "make" does:
1 Look around for a dependancy file called fubar.c.
IF it exists THEN
"build fubar.c" in case it needs it.
2 IF fubar.o exists AND fubar.c exists AND
fubar.c is younger than fubar.o
THEN
Compile fubar.c
ELSE
do nothing: "fubar.o is up to date"
But what about further dependancies such as #include files?
"make" handles this by parsing a Makefile script which lists
all the dependancies. In OO terms the dependancy list of a target
is a property of the object. So too are the command lines required
to re-build the object. They constitute that object's individual
"build" method.
For example, to build executable programs with oosh, each
".exe" will need its dependancy list, and a command sequence
to link or compile the components together. This could be
implemented by the following scheme:
* Each buildable object consists of a compound object
having its own directory.
* The component objects are listed in a file "./depends"
* The command script required to build the object
is in the object's "./methods/build_after" method file.
* The method for this class of object first executes
the "build" method for all the components in "./depends",
IF any of the components are younger than the target object
THEN
the object's own "build_after" method is invoked.
In practice "make" programmers almost always use one directory
per executable, so this approach is familiar. Keeping the
source and build files of an library or program together
in one directory is common. Are the source files that make
up a program also to be viewed as private objects of that
program?
7 CONCLUSIONS
This prototype OO shell is exciting, but many practical problems
remain to be addressed. For example, oosh needs to be
faster, thus a compiled implementation is indicated. Oosh is
not efficient in its use of OS resources, requiring many files
and directories to store objects.
Also, oosh cannot handle lists of objects, it does not cope
well with command line switches. Is it possible to devise
command line switches that can be meaningful to a large
number of classes? Neither is there provision for methods that
require more than one object of different classes.
Despite these limitations in this simple prototype I feel that
it shows that an Object Oriented shell is a helpful tool
and fits naturally to the programming task. It also shows
that an OO Shell will eventually replace "make" and its ilk.
APPENDIX A Source Code
A.1 "dispatch.sh"
1 #!/bin/sh
2 method=`basename $0`
3 #
4 object=`pwd`/$1
5 base=`basename $object`
6 suffix=`echo $object | sed -f /u/bill/oosh/bin/suffix.sed`
7 echo method: $method object: $object suffix $suffix marg $marg
8 if test -r /u/bill/oosh/classes/$suffix
9 then
10 cd /u/bill/oosh/classes/$suffix
11 else
12 cd /u/bill/oosh/classes/top
13 fi
14 cd `pwd` # Adjust soft links
15 /u/bill/oosh/bin/tryit.sh $method $object $suffix $args $marg
A.2 "tryit.sh"
1 #!/bin/sh
2 # tryit.sh
3 method=$1
4 object=$2
5 class=$3
6 #
7 #
8 #
9 if test `pwd` = /u/bill/oosh
10 then
11 echo cannot find method $method for $object
12 else
13 if test -x methods/$method
14 then
15 methods/$method $object
16 else
17 cd ..
18 /u/bill/oosh/bin/tryit.sh $method $object $class $margs
19 fi
20 fi
21
A.3 "top/methods/defclass"
1 #!/bin/sh
2 object=$1
3 super=$2
4 class=`echo $3 | sed -f /u/bill/oosh/bin/suffix.sed`
5 echo super $super class $class 4 $4
6 if test -d /u/bill/oosh/classes/$super
7 then
8 cd /u/bill/oosh/classes/$super
9 cd `pwd`
10 if test -d $class
11 then
12 echo defclass: $class probably exists already
13 else
14 mkdir $class
15 mkdir $class/methods
16 ln -s `pwd`/$class /u/bill/oosh/classes/$class
17 fi
18 else
19 echo defclass: $super does not exist
20 fi
A.4 "top/methods/defmethod"
1 #!/bin/bsh
2 object=$1
3 method=$2
4 class=$3
5 exec=$4
6 echo defmethod: method $method class $class exec $exec
7 if test ! -x /u/bill/oosh/bin/$method
8 then
9 ln -s /u/bill/oosh/bin/dispatch /u/bill/oosh/bin/$method
10 fi
11 if test -d /u/bill/oosh/classes/$class
12 then
13 cd /u/bill/oosh/classes/$class
14 cd `pwd`
15 if test -d ./methods
16 then
17 rm ./methods/$method
18 cp $exec ./methods/$method
19 else
20 echo defmethod: missing methods directory in `pwd`
21 fi
22 else
23 echo defmethod: Class $class does not exist
24 fi
--
Automatic Disclaimer:
The views expressed above are those of the author alone and may not
represent the views of the IBM PC User Group.
--
More information about the Comp.unix.programmer
mailing list