language design for system vs. application implementation
David Hough
uunet!Eng.Sun.COM!David.Hough
Thu Dec 19 10:05:07 PST 1991
While struggling recently with several unrelated issues, including
this one relevant to NCEG:
What's the right level of functionality for numerical support in
programming languages?
I came to the conclusion that a fundamental problem was attempting to
provide two levels of abstraction with one programming language. There
really are two distinct levels of programming languages, which I call System
Implementation Language and Application Implementation Language. A lot of
confusion results from trying to make one language serve both levels.
Levels of Abstraction
Consider the following levels and corresponding interfaces:
Interface Layer Example
CPU+FPU R4000 or 586
electrical signals
minimum hardware platform Sun IPC
instruction set architecture
supervisor code Unix kernel
supervisor call interface
System Implementation Language
(SIL) implementation platform -
written in SIL:
SIL compiler C
SIL standard library stdio
Application Implementation Language
(AIL) implementation platform -
written in SIL:
AIL compiler C++
AIL standard libraries class library
Application implementation platform -
written in AIL:
application libraries multi-media
libraries
application for end users multi-media application
graphical user interface
This picture is imperfect - some aspects of instruction set architecture
permeate many levels. But in general the design of each level could be con-
sidered defective to the extent that it required cheating on the normal inter-
face to obtain optimal performance. By this measure most existing languages
come up short.
How are system implementation languages and application implementation
languages different? The fundamental distinction is that application levels
are for solving problems directly of interest to end users, and system levels
are for solving lower level problems that arise indirectly from using comput-
ers to solve end user problems. Consequently application level languages try
not to get in the way of the application programmer's thinking about the ulti-
mate problem, while system level languages try not to get in the way of the
system programmer's thinking about the machine and low-level software.
The SIL has two parts - the "portable" part that generates machine
instructions and supervisor calls that are universal, or nearly so, and the
"specific" part that generates machine instructions peculiar to a particular
CPU and supervisor calls peculiar to a particular kernel. In principle, one
command line option should disable features generating "specific" stuff, to
help in creating portable code, and another should disable features generating
supervisor calls, to help in creating supervisor code. Perhaps this can be
accomplished by having operator syntax and similar low-level language con-
structs for the features that have universal machine instruction representa-
tions, and function call syntax for everything else. The compiler for a
specific SIL interface should be very highly optimizing for that platform.
Specific features in functional notation should be compiled as efficiently as
explicit operators (rather than compiled into actual function calls) whenever
appropriate. SIL compilers know a lot about their target platform.
The SIL can be a subset of the AIL, in principle, although I doubt that
this would make an outstanding design. In any event, the common data types
should be implemented identically; calling sequences should be identical for
identical types.
What features vary between SIL and AIL? The flavor of SIL is represented
by:
no dynamic types
explicit storage management
support for intercepting hardware traps at lowest level
consistent with system integrity
explicit minimal multi-thread primitives
strong type checking easily bypassed
static "hard-compiled" tendency
varargs is questionable
it's easy to express hardware and supervisor primitives
while the flavor of AIL is represented by:
dynamic types (character strings, array temporaries)
implicit garbage collection
built-in signal and exception handling
nested functions
implicit multi-thread support
implicit multi-tasking
strong type checking enforced
dynamic "interpretive" tendency
varargs is natural
it's easy to express application primitives
To demonstrate the difference in another way, consider that at the
current level of practice, floating-point addition and multiplication are
primitive SIL operators, while matrix-multiplication would be an AIL primi-
tive. Vector operations are trickier: they are common but not universal in
instruction sets of interesting machines, so a case could be made for defining
them in SIL in a syntax that was portable but might be implemented in hardware
or software.
It sounds reasonable to implement an AIL with a translator into SIL -
C++, Modula-3, Fortran-77, and Fortran-90 have all been implemented as trans-
lators into C. So whatever its other faults, C can be used as a SIL. This is
only faint praise, for the same can be said of Fortran-66: until Fortran-77
became popular, a number of computational languages were implemented as trans-
lators into Fortran-66. The enabling feature shared by C and Fortran-66 as
SIL's was ubiquity on the target platforms of interest.
This translation model enforces either that all AIL's contain only
features expressible in the SIL - or else that the SIL must be able to imple-
ment all features of all AIL's.
Possible Implications
For NCEG: Array extensions should not include matrix multiplication.
Complex arithmetic is questionable.
Since presubstitution is not likely to be implemented in hardware, it
should not be specified as part of NCEG C - the minimal support to recover
after hardware traps is what should be specified. Conversely one might
argue that since presubstitution might well be implemented as a kernel ser-
vice, that interface should be part of NCEG C.
Generally:
Nowadays instruction set architectures are designed to rapidly execute
existing programs in C and Fortran, while the evolution of C and Fortran is
influenced by existing instruction set architectures. This self-referential
recursion could presumably only be broken by a vendor of integrated systems,
yet integrated systems vendors are tending toward fragmentation based on
proprietary implementations of frozen public interfaces.
More information about the Numeric-interest
mailing list