The purpose of
the Smalltalk project is to provide computer support for the creative
spirit in
everyone. Our work flows from a vision that includes a creative
individual and
the best computing hardware available. We have chosen to concentrate on
two
principle areas of research: a language of description (programming
language)
that serves as an interface between the models in the human mind and
those in
computing hardware, and a language of interaction (user interface) that
matches
the human communication system to that of the computer. Our work has
followed a
two- to four-year cycle that can be seen to parallel the scientific
method:
Modularity: No component in a complex system should depend
on the
internal details of any other component.
 |
Figure 2: System complexity. As the number of
components in
a system increases, the chances for unwanted interaction increase
rapidly.
Because of this, a computer language should be designed to
minimize the
possibilities of such interdependence. |
This principle is depicted in figure
2. If there are N components in a system, then there are
roughly
N-squared potential dependencies between them. If computer
systems are
ever to be of assistance in complex human tasks, they must be designed
to
minimize such interdependence. The message-sending metaphor provides
modularity
by decoupling the intent of a message (embodied in its name) from
the
method used by the recipient to carry out the intent. Structural
information is similarly protected because all access to the internal
state of
an object is through this same message interface.
The
complexity of a system can often be reduced by grouping similar
components. Such
grouping is achieved through data typing in conventional programming
languages,
and through classes in Smalltalk. A class describes other objects
--
their internal state, the message protocol they recognize, and the
internal
methods for responding to those messages. The objects so described are
called
instances of that class. Even classes themselves fit into this
framework;
they are just instances of class Class, which describes the
appropriate
protocol and implementation for object description.
- Classification: A language must provide a means for
classifying
similar objects, and for adding new classes of objects on equal
footing with
the kernel classes of the system.
Classification is the
objectification of nessness. In other words, when a human sees a
chair,
the experience is taken both literally an "that very thing" and
abstractly as
"that chair-like thing". Such abstraction results from the marvelous
ability of
the mind to merge "similar" experience, and this abstraction manifests
itself as
another object in the mind, the Platonic chair or chairness.
Classes are the chief mechanism for extension in
Smalltalk. For instance, a music system would be created by adding new
classes
that describe the representation and interaction protocol of Note,
Melody, Score, Timbre, Player, and
so on.
The "equal footing" clause of the above principle is important because
it
insures that the system will be used as it was designed. In other words,
a
melody could be represented as an ad hoc collection of Integers
representing pitch, duration, and other parameters, but if the language
can
handle Notes as easily as Integers, then the user will
naturally describe a melody as a collection of Notes. At each
stage of
design, a human will naturally choose the most effective representation
if the
system provides for it. The principle of modularity has an interesting
implication for the procedural components in a system:
- Polymorphism: A program should specify only the behavior
of
objects, not their representation.
A
conventional statement of this principle is that a program should never
declare
that a given object is a SmallInteger or a LargeInteger,
but
only that it responds to integer protocol. Such generic description is
crucial
to models of the real world.
Consider an
automobile
traffic simulation. Many procedures in such a system will refer to the
various
vehicles involved. Suppose one wished to add, say, a street sweeper.
Substantial
amounts of computation (in the form of recompiling) and possible errors
would be
involved in making this simple extension if the code depended on the
objects it
manipulates. The message interface establishes an ideal framework for
such an
extension. Provided that street sweepers support the same protocol as
all other
vehicles, no changes are needed to include them in the simulation:
- Factoring: Each independent component in a system would
appear
in only one place.
There are many reasons for this
principle.
First of all, it saves time, effort, and space if additions to the
system need
only be made in one place. Second, users can more easily locate a
component that
satisfies a given need. Third, in the absence of proper factoring,
problems
arise in synchronizing changes and ensuring that all interdependent
components
are consistent. You can see that a failure in factoring amounts to a
violation
of modularity.
Smalltalk encourages well-factored
designs
through inheritance. Every class inherits behavior from its
superclass.
This inheritance extends through increasingly general classes,
ultimately ending
with class Object which describes the default behavior of all
objects
in the system. In our traffic simulation above, StreetSweeper
(and all
other vehicle classes) would be described as a subclass of a general
Vehicle class, thus inheriting appropriate default behavior and
avoiding repetition of the same concepts in many different places.
Inheritance
illustrates a further pragmatic benefit of factoring:
- Leverage: When a system is well factored, great leverage
is
available to users and implementers alike.
Take
the case of sorting an ordered collection of objects. In Smalltalk, the
user
would define a message called sort in the class
OrderedCollection. When this has been done, all forms of
ordered
collections in the system will instantly acquire this new capability
through
inheritance. As an aside, it is worth noting that the same method can
alphabetize text as well as sort numbers, since comparison protocol is
recognized by the classes which support both text and numbers.
The benefits of structure for implementers are
obvious.
To begin with, there will be fewer primitives to implement. For
instance, all
graphics in Smalltalk are performed with a single primitive operation.
With only
one task to do, an implementer can bestow loving attention on every
instruction,
knowing that each small improvement in efficiency will be amplified
throughout
the system. It is natural to ask what set of primitive operations would
be
sufficient to support an entire computing system. The answer to this
question is
called a virtual machine specification:
- Virtual Machine: A virtual machine specification
establishes a
framework for the application of technology.
The
Smalltalk virtual
machine establishes an object-oriented model for storage, a
message-oriented
model for processing, and a bitmap model for visual display of
information.
Through the use of microcode, and ultimately hardware, system
performance can be
improved dramatically without any compromise to the other virtues of the
system.
User Interface
A
user
interface is simply a language in which most of the communication is
visual.
Because visual presentation overlaps heavily with established human
culture,
esthetics plays a very important role in this area. Since all capability
of a
computer system is ultimately delivered through the user interface,
flexibility
is also essential here. An enabling condition for adequate flexibility
of a user
interface can be stated as an object-oriented principle:
- Reactive Principle: Every component accessible to the
user
should be able to present itself in a meaningful way for observation
and
manipulation.
This criterion is well supported by the
model of
communicating objects. By definition, each object provides an
appropriate
message protocol for interaction. This protocol is essentially a
microlanguage
particular to just that kind of object. At the level of the user
interface, the
appropriate language for each object on the screen is presented visually
(as
text, menus, pictures) and sensed through keyboard activity and the use
of a
pointing device.
It should be noted that
operating
systems seem to violate this principle. Here the programmer has to
depart from
an otherwise consistent framework of description, leave whatever context
has
been built up, and deal with an entirely different and usually very
primitive
environment. This need not be so:
- Operating System: An operating system is a collection of
things
that don't fit into a language. There shouldn't be one.
Here
are
some examples of conventional operating system components that have been
naturally incorporated into the Smalltalk language:
- Storage management -- Entirely automatic. Objects are created by a
message
to their class and reclaimed when no further references to them exist.
Expansion of the address space through virtual memory is similarly
transparent.
- File system -- Included in the normal framework through
objects such as
Files and Directories with message protocols that
support
file access.
- Display handling -- The display is simply an instance of
class
Form, which is continually visible, and the graphical
manipulation
messages defined in that class are used to change the visible image.
- Keyboard Input -- The user input devices are similarly
modeled as objects
with appropriate messages for determining their state or reading their
history
as a sequence of events.
- Access to subsystems -- Subsystems are naturally incorporated
as
independent objects within Smalltalk: there they can draw on the large
existing universe of description, and those that involve interaction
with the
user can participate as components in the user interface.
- Debugger -- The state of the Smalltalk processor is
accessible as an
instance of class Process that owns a chain of stack frames.
The
debugger is just a Smalltalk subsystem that has access to manipulate
the state
of a suspended process. It should be noted that nearly the only
run-time error
that can occur in Smalltalk is for a message not to be recognized by
its
receiver.
Smalltalk has no "operation
system" as
such. The necessary primitive operations, such as reading a page from
the disk,
are incorporated as primitive methods in response to otherwise normal
Smalltalk
messages.
Future Work
As
might be
expected, work remains to be done on Smalltalk. The easiest part to
describe
is the continued application of the principles in this paper. For
example, the
Smalltalk-80 system falls short in its factoring because it supports
only
hierarchical inheritance. Future Smalltalk systems will generalize
this model
to arbitrary (multiple) inheritance. Also, message protocols have not
been
formalized. The organization provides for protocols, but it is
currently only
a matter of style for protocols to be consistent from one class to
another.
This can be remedied easily by providing proper protocol objects that
can be
consistently shared. This will then allow formal typing of variables
by
protocol without losing the advantages of polymorphism.
The other remaining work is less easy to articulate. There are clearly
other
aspects to human thought that have not been addressed in this paper.
These
must be identified as metaphors that can complement the existing
models of the
language.
Sometimes the advance of computer
systems
seems depressingly slow. We forget that steam engines were high-tech
to our
grandparents. I am optimistic about the situation. Computer systems
are, in
fact, getting simpler and, as a result, more usable. I would like to
close
with a general principle which governs this process:
- Natural Selection: Languages and systems that are of
sound
design will persist, to be supplanted only by better ones.
Even
as
the clock ticks, better and better computer support for the creative
spirit is
evolving. Help is on the way.