This is one of the
STIPPLE Documentation pages.
STIPPLE Rationale
The rationale roughly follows the outline of
the reference manual. Thus, appendix section
A.1 roughly corresponds to chapter 1, appendix
section to chapter 3, etc.
Introduction
STIPPLE stands for Strongly-Typed
Internationalizable Parameterized
Programming Language, Extensible.
The intention is to make STIPPLE readily available
to the public. By making STIPPLE a registered
trade-mark, I have some legal recourse on the
use of the STIPPLE programming language.
The reasons for improving programmer productivity are:
-
Programming is a difficult enterprise; any
tools that ease the task are appreciated
by the programmers.
-
In general, there are not enough programmers
to do all of the tasks that need to be done;
thus, it is wise to attempt to get more out
of each programmer.
-
Improved software quality results in results
in both happier customers and programmers who`
do not have to spend as much time on maintenance.
-
Programming is both time-consuming and expensive;
a better language can reduce both.
The reasons for static type-checking are:
-
Errors detected at compile time do not have
to be discovered at run time.
-
With dynamically type checked code, it is
possible to ship code with type errors to
customers, whereas with statically type
checked code, it is not.
-
Dynamically typed code incurs extra overhead.
The arguments in favor of dynamically type-checked code are:
-
There are interesting programs that are more
easily expressed in a dynamically type checked
language. However, there are many, many programs
that can quite easily and conveniently be
expressed using a statically typed language.
STIPPLE should only be used to express programs
that are in the latter category.
-
Statically type checked are by necessity more
verbose than dynamically type checked ones.
Some of verbosity is useful for documentation
purposes, but the rest is only of interest to
the compiler.
For STIPPLE, it is felt that the cost-benefit ratio
for static type checking versus dynamic type checking
is in static type checking's favor. In addition, if
it is desired, there is a relatively easy way to
achieve dynamic type checking in STIPPLE.
Parameterized types are a pretty complicated feature
to add to any programming language. In addition, they
tend to be used primarily for lower level abstractions
such as lists, vectors, tables, trees, sets, etc.
However, they are extremely useful for these low-level
abstractions. In a strongly typed language without
either parameterization or typecasts, it is necessary
for the programmer to duplicate code for different
instantiations of these low-level abstractions.
Duplicated code wastes space, is error prone and
is difficult to maintain. Thus, even though good
type parameterization is difficult to add to a
language, it appears to be worthwhile.
Referential integrity is accomplished by ensuring
that there are never any variables or objects that
contain values that do not point to objects of the
correct type.
The reasons for referential integrity are:
-
A program with referential integrity can not
"dump core".
-
It is possible to implement a debugger that
esides in the same address space as the STIPPLE
application without having to worry about whether
the application can damage any of the debugger's
data structures. This makes implementing a STIPPLE
debugger much easier. The net result is that the
initial STIPPLE system comes complete with a
debugger.
Referential integrity is accomplished by ensuring
that there is always at least one object of every
type that is assigned etc.
The advantages of garbage collection are:
-
The programmer does not have to write code to
manually release unneeded storage; instead this
code is written once by the STIPPLE implementor.
-
Garbage collection helps to ensure referential
integrity thereby ensuring that the application
will not "dump core" (see
Why referential integrity.)
-
Garbage collection simplifies interfaces between
modules by making it unnecessary to discuss which
routines in an interface allocate and deallocate
storage.
-
Programmers no longer have to spend as much time
worrying about storage leaks. It should be noted
that a programmer can still write a program that
suffers from memory leaks, even thought the
language is garbage collected.
-
For larger applications, the amount of code to
implement a good garbage collector is frequently
quite a bit less than the amount of code written
for manual deallocation.
The disadvantages of garbage collection are:
-
Garbage collection can be less efficient than
hand-coded storage releasing.
-
Some programmers use the existence of garbage
collection as an excuse to be very sloppy about
memory is allocation. Such programs can perform
poorly, and the garbage collector is unfairly
blamed for the poor performance, when in fact
it is the programmer who is at fault. It should
be noted that inefficient code can be written
in any programming language.
-
There are real-time applications for which the
cost of garbage collection is too high.
Obviously, such applications should not be
written in STIPPLE.
-
A poor implementation of garbage collection can
cause a "pregnant pause" when the garbage collector
is implemented. Luckily, there exist garbage
collection implementations which do not have this
attribute.
There is plenty of evidence in the literature that
defining clean, well-defined interfaces to the data
and algorithms that make up a program enhances its
maintainability. Anything that improves program
maintainability directly improves programmer
productivity, since programmers spend a great
deal of time maintaining code.
The STIPPLE language is a little different from
other languages in that the interface definitions
are not kept in separate files. Instead, the STIPPLE
compiler has the ability to directly extract the
interface information from the source code that
defines a module. Another compiler mode enables
the extraction of the module documentation.
The term "object-oriented" is ill defined. STIPPLE
definitely has objects and operations on those objects;
it also supports a restricted form of inheritance; it
definitely does not support the C++ model of static
and dynamic inheritance. So depending upon your
definition of what features must be in an object
oriented language, STIPPLE either is or is not
"object-oriented."
The most important feature that STIPPLE supports
is the concept of data abstraction. The literature
abounds with evidence that cleanly separating the
implementation of an abstraction from its use
improves code comprehensibility and maintainability.
It is the data abstraction aspects of object-oriented
programming that is directly supported by STIPPLE.
For some people, type inheritance (i.e. sub-classing)
is the most critical aspect of an object-oriented
programming language. STIPPLE supports explicit
static inheritance (including multiple inheritance.)
It is explicit in the sense that each "sub-class"
must completely list all of the operations it supports.
By making everything explicit, the user of a "sub-class"
need only look at the "sub-class" definition to know
what it can and can not do. Dynamic inheritance stores
the pointer to a virtual function table with each
object. While STIPPLE permits the user to manually
construct and access a virtual function table, it
does not provide much assistance in constructing
such tables. The operation vectors provided by
parameterized types are the closest construct to
virtual function tables produced by STIPPLE.
It is very difficult to write a routine that does
not have any failure modes. Without exception handling,
the way failure modes are communicated to the user of
a routine is done in an ad hoc fashion (e.g. returning
a special value and testing for it at the call site.)
With a language supported exception handling scheme,
the interfaces to routine failures are well defined
and consistent.
STIPPLE supports a single-level termination model for
exceptions. When a routine signals an exception,
control is transferred to an appropriate exception
handler in the caller. Some languages support the
continuation model of exceptions where the exception
handler can return control back to the signal point.
This model was rejected due to its complexity and
relative lack of utility.
A multi-level exception model permits a signal
handler to reside several levels up in the call
stack. The multi-level model was rejected because
it violated data abstraction and could easily leave
behind damaged data structures. The STIPPLE resignal
statement provides an easy way of passing a signal
through a routine.
Programming is an international profession. It
seems rather silly to ask a bunch of programmers
that live in a country and speak its native
language to write programs in English or mixed
English and another language. None-the-less,
that is currently what happens, since current
compilers require that all keywords be written
in English. STIPPLE provides keywords in the
native language. In order to support this feature,
STIPPLE always spells keywords in their entirety
so that they can be easily translated to different
languages.
The STIPPLE compiler also has a mode that helps
translate code from one native language to another.
This is accomplished with the aid of a manually
created translation table that provide translations
for comments and symbols within a given program.
This enables the development and maintenance of
software between people who do not use the same
native language.
There is an international market for software. In
order to meet this market, applications must be
designed so that they can be localized to a particular
native language. STIPPLE directly supports this
ability to localize programs by providing two
kinds of string literals and a special kind of
comment called a translation hint comment. String
literals enclosed in single quotes are meant to
be translated for localization, whereas string
literals enclosed in double quotes are not
translated. There is a compiler mode that
extracts a table of translation hints and
translatable strings. Somebody manually
translates the strings using the translation
hints as guide. These translated strings can
be picked and used up by the application without
requiring any recompilation or relinking.
It is very hard for a proprietary language to succeed.
Most organizations are unwilling to write software in
a programming language that is only available from a
single source (unless, of course, they are the source
of the language.) While a language can succeed if the
first implementation is not freely available (e.g.
PostScript), it has a greater chance of seceding if
the first implementation is freely available. If
making money is an objective, publishing the definitive
reference manual is always a possibility.
A new programming language that can not be run a wide
variety of machines is not competitive with languages
that are. For this reason, STIPPLE is portable. Extra
effort has gone into the ANSI-C code generator to make
the resulting code quite readable.
Programmers are human and they write buggy programs.
A portable compiler without a portable debugger only
solves half of the portability problem. By providing
a portable debugger, it is that much easier for people
to adopt STIPPLE.
All successful languages evolve over time. The ready
availability of the basic STIPPLE compiler in source
code form should encourage the experimentation of
various language features. STIPPLE is architected
to support this experimentation. This is accomplished
by structuring the syntax to easily support the
addition of new keywords without breaking existing
programs (i.e. keywords are not reserved words as
they are in most compilers.) In addition, STIPPLE
has the version and extension declarations. The
version declaration is required for every source
file and it specifies which version the language
the source code is written in (e.g. "1.0", "1.1",
"2.0", etc.) The extension declaration is used to
explicitly enable a named language extension that
has been added to the compiler. When an extension
gains wide-spread acceptance, it is folded into
the basic compiler and the compiler version number
is incremented.
Word processors have a number of features that are
not found in the typical plain text editor. These
features include the ability change fonts, draw
pictures, create tables, check spelling, etc. All
of these features can be used to increase the
readability and maintainability of software. For
this reason, STIPPLE permits code to be written
using a word processor.
Overview
Without the concept of an iterator, some abstract
data types have to expose more of the internal
representation to the user than is necessary.
Alternatively, they have to cobble together
their own way of doing iteration. It is better
to make iterators a first-class concept in the
language so that everybody uses the same way
to implementing them.
Iterators can be thought of as co-routines that
are executed inside of loops.
The requirements and desirable characteristics
for iterators are:
-
They must be able to yield zero, one, or more
values. Each iteration will always yield the
same number of values. Iterators that yield
no values are expected to be extremely rare.
-
They must be able to return zero, one, or more
values when they terminate. It is expected that
return values will be the exception rather than
the rule.
-
When an iterator loop is terminated by a break,
continue, go_to, while, until, go_to, or signal
statement, control must be passed back to the
iterator so that it can clean-up its state.
-
It is desirable to be able to have more than
one iterator active at a time.
The overall goal of STIPPLE is to have referential
integrity. This means that when a composite type is
created it must have all of its pointers initialized
to point to a valid object. One solution to this
problem is to have a constructor syntax that requires
the programmer to provide initial values for all of
the pointers when a composite object is created. For
recursive record types, there is a "chicken-and-egg"
problem. (The next and previous fields in a doubly
linked list are obvious examples of recursive record
types.) Since an instance of the recursive record
type is needed to create another instance of the
type, there is no way to create the first instance.
In CLU, it was necessary to break the data structure
recursion with some sort of variant. Initial objects
solve the recursive record problem rather elegantly.
Since STIPPLE initializes all composite objects to
point to initial objects at create time for
referential integrity purposes, there is no need
to have syntax that combines object creation with
object initialization. However, for record types
it is still useful to have to have the ability
to force the explicit initialization of all
fields. A common cause of bugs is adding a
field to a record type and then forgetting to
initialize the field in all locations where
the record is created. In order to combat this
common bug, STIPPLE provides the initialize
statement.
Lexical Issues
The reason for explicitly using indentation is to
make it possible for the compiler resilient to single
character errors, such as, missing semicolons (`;'),
missing braces (`{', `}'), missing parenthesis
(`(', `)'), etc. By requiring that the program
be properly indented, whenever the compiler is
having problems parsing a statement, it can give
up and continue to the next statement. Another
advantage of using indentation is that it
eliminates a whole discussion of where to put
braces.
The reasons for using sharp (`#') for comments are
-
because most programs under Unix use it for
comments in input files.
-
it only occupies one character. The C style
(`/* ... */') and Pascal style (`(* ... *)')
comments were rejected because they required
four characters. In addition, a missing comment
terminator has the problem of swallowing large
program regions and producing really difficult
to understand error message.
-
it is not used for any other purpose in the
language. The C++ style comment (`//') can be
inadvertently entered where a division operator
was intended (e.g., a := b / c + d // e + f
/ g + h / i.) This kind of error can be really
difficult to discover.
-
it conflicts with the C preprocessor. The valid
reasons for using the C preprocessor are defining
constants, function in-lining, and conditional
compilation. Since all of these features are
directly supported by the STIPPLE compiler,
there is no valid reason for using the C
preprocessor. By making the comment character
be a sharp (`#'), people will not easily be able
to use the C preprocessor on STIPPLE programs.
If an organization ever decides that it is going
to maintain translated versions of code, it may
have a totally separate department that is responsible
for doing comment translations. (In general, it is
doubtful that a having a separate translation
department will yield the greatest of translations.)
By translating the program identifiers separately
from the rest of the comments, a programmer can
change an identifier without causing all comments
that use it to be gratuitously retranslated by the
translation department.
The reason for always using full words and phrases
in STIPPLE keywords is to make it easier to translate
the keywords into another language.
The primary reason why keywords are not reserved is
to support extensibility. If keywords are reserved
identifiers, an extension that needs to add a new
keyword might break existing programs that already
use the keyword as a regular identifier. Another
reason is because people sometimes forget that they
are using a reserved word as an identifier; the
resulting error messages can be quite confusing.
(For example, for a long time the keyword entry
was reserved in C, but not used for anything. The
error messages that resulted from using entry as
an identifier could be quite confusing.)
Notational Issues
The Prelude Declarations
The order in which declarations are specified is
constrained because helps improve uniformity between
code. With the exception of requiring the language
and version declarations to be first, there is no
technical reason for imposing an order on the
declarations.
In a production environment, there is a need
to recompile an application to support multiple
different configurations. If conditional
compilation is not directly supported by the
language, it will be grafted on via a macro
preprocessor. By making conditional compiliation
be directly supported by the compiler, it is
better integrated into the language.
Why variadic procedures
Type Declarations
Routine and Object Declarations
Some implementations of a parameterized procedure
will need to define variables with same types as
the parameters. Sometimes the definition of a
variable needs to be initially assigned the initial
object for the type. If the initial object for
parameters where not implicitly passed in via a
needs/variadic_needs clause, they would have to
be explicitly specified in the needs/variadic_needs
clause. The problem with explicit specification
is that it is reflecting the implementation of a
procedure up to the abstract procedure interface.
Thus, if an implementor suddenly decides they need
the initial object for a parameterized type, they
would have to change the procedure's abstract
interface. It seems incorrect to have changes in a
procedures implemention require changes to its
abstract interface and the subsequent recompilation
of the code at all its use sites. This is the reason
why the initial objects for parameterized types are
implicitly passed in for needs/variadic_needs clauses.
There are two reasons for supporting variadic
procedures in STIPPLE, despite their obvious
complexity. First, they seem to provide the
best solution to support internationalized
print strings. Second, there are some applications
that can naturally use variadic procedures.
In C, output is frequently done using a function
called printf. The printf function takes a format
string, followed by a list of arguments to be
printed. The format string is printed
character-by-character to the output until a
percent character (`%') is encountered. At this
time the next argument is printed to the output
stream uses the letter following the percent
character (`%') to specify the output format
for the argument. (Additional characters between
the percent and the letter specify additional
formatting control.) In additions, the X/Open
version of printf permits the user to specify
format strings that print arguments out of order.
This feature is used for internationalization
because it permits the person doing localization
to print output in a form more natural for the
local language. A draw-back of the X/Open
feature is that a mistake in the localization
can cause the application to dump core if the
wrong argument type is specified (e.g. string
instead of integer.)
One major problem with the printf function is that
it only supports the output of base types. C++
addresses this problem with streams and the
overloading of left shift operator (`<<').
Unfortunately, the order of text and arguments
is hard coded into the application and is
unchangeable by the localization process.
For this reason, the C++ solution is not
acceptable for STIPPLE.
Statements
Expressions
From here you can backt to the
table of contents.
Copyright (c) 1991 --
Wayne C. Gramlich. All rights reserved.