home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
High Voltage Shareware
/
high1.zip
/
high1
/
DIR9
/
A9X_0610.ZIP
/
9XOVERVW.HLP
< prev
next >
Wrap
Text File
|
1993-06-10
|
25KB
|
534 lines
Form S101-0892a
9XOVERVW.HLP
Ada Information Clearinghouse, 1-800-AdaIC-11, 703/685-1477
An Overview of Ada 9X
S. Tucker Taft
Ada 9X Mapping/Revision Team
Intermetrics, Inc.
733 Concord Avenue
Cambridge, MA 02138
1. Introduction
The Ada programming language, originally approved as an ANSI/MIL standard in
1983, and an ISO standard in 1987, is being revised in accordance with ANSI
and ISO procedures, with a target date for balloting on the revised standard
in 1993. The revised language is currently designated "Ada 9X" and is being
developed through the collaborative efforts of a number of Ada 9X Project
Teams under the leadership of Christine Anderson at Eglin Air Force Base (now
at Kirtland AFB). The Project Teams include:
* The Distinguished Reviewer (DR) Team
* The Revision Requirements Team
* The Mapping/Revision Team (MRT)
* The User/Implementor Teams (the UI Teams)
* The Implementation Analysis Team (IAT)
* The Language Precision Team (LPT)
* The Ada Compiler Validation Capability (ACVC) Team
In addition, individuals and corporations throughout the world are
participating in public reviews of the documents produced by the various
teams.
Intermetrics, Inc., is the prime contractor for the Mapping/Revision Team,
with consultants from the Software Engineering Institute, Argonne National
Laboratory, Computer Sciences Corporation, the British National Physical
Laboratory, as well as several private consultants. The Mapping/Revision Team
is responsible for proposing specific language changes in response to the
Revision Requirements Document (December 1990) produced by the Requirements
Team, and then revising the Ada Reference Manual to reflect the changes
ultimately selected for inclusion in Ada 9X.
The remainder of this extended abstract discusses some of the proposals of the
Mapping/Revision Team, focusing on those proposals that provide the most
significant enhancement to the utility of the language. An expanded form of
this paper [has later appeared] in a ... special issue of Communications of
the ACM on the Ada programming language.
2. Overview of Changes
The Ada 9X Mapping/Revision Team has proposed changes in the following three
basic areas:
* Object-Oriented Programming
* Programming in the Large
* Real-Team and Parallel Programming
2.1. Object-Oriented Programming
Ada 83 has been called an "object-based" language, but it does not qualify as
a true "object- oriented" language because it lacks full support for
inheritance and run-time polymorphism. For Ada 9X, we have proposed to
generalize the existing "object-based" features of Ada to allow them to fully
support object-oriented programming.
Ada 83 has a rich abstract type definition capability. Furthermore, it allows
one type to be defined as a "derivative" of another. However, it does not
allow additional components to be added to the type as part of this
derivation. For Ada 9X, we are generalizing the type derivation capability by
allowing private and record types to be "extended" with additional components.
For example, in Ada 83 a new type may be defined in terms of an existing type
as follows:
type Fancy_Window is new Basic_Window;
This new type (Fancy_Window) inherits the same set of components as
Basic_Window, and the same set of "primitive" operations. In addition, new
operations may be defined, and inherited operations may be overridden.
For Ada 9X, we allow new components to be defined as part of a type
derivation, as follows:
type Fancy_Window is new Basic_Window
with record
Border_Width : Pixel_count := 1;
Border_Color : Color := Black;
end record;
Now, the new type Fancy_Window has all of the components of a Basic_Window,
plus two additional components to allow more control over the appearance of
the border. If the names and types of these new components are to be kept
"private" to the package in which the derived type is defined, a private
extension part may be specified:
type Fancy_Window is new Basic_Window with private;
In the "private" part of the package, the actual components of the extension
part must be specified.
Because of Ada 83's preexisting support for derived types, this modest
generalization is adequate to provide full support for what is called "single
inheritance." However, to provide run-time polymorphism, additional language
enhancements are required. We used the existing Ada 83 concept of "universal"
types and type "classes" as the basis for our proposals for run- time
polymorphism.
In Ada 83, integer literals are defined to be a "universal" integer type,
which implicitly convertible to any integer type. Similarly, real literals
are defined to be of a universal real type, convertible to any real type. The
set of all integer types forms the integer "class" of types in Ada 83.
Similarly, the set of all real types forms the real "class."
For Ada 9X, we have generalized the concept of "class" to refer to any set of
types formed from the direct and indirect derivatives of a given type.
Furthermore, we have generalized the universal numeric type concept to the
concept of a "class-wide" type, which can be used to define universal or
"class-wide" operations that are as convenient to use with any type in a
class, as are integer literals with any type in the integer class.
Such a generalized "class-wide" type is named using attribute notation: For
any "specific" type T, the "class-wide" type T'CLASS exists and may be used to
define class-wide operations, and class-wide access types. For example, given
our Basic_Window type above, the class-wide type Basic_Window'CLASS exists,
and may be used to define operations that manipulate objects of type
Basic_Window or any type derived from it, as follow:
procedure Flash_Window(W : Basic_Window'CLASS) is
-- This "class-wide" operation flashes a window
-- by using its Hide and Display primitive operations
-- repeatedly.
begin
Hide(W);
Display(W);
Hide(W);
Display(W);
end Flash_Window;
Because the formal parameter type is Basic_Window'CLASS, the Flash_Window
operation may be applied to any object whose type is in the "class" of type
descended from Basic_Window. Note that the implementation of a class-wide
operation normally uses the "primitive" operations of the "root" type
(Basic_Window), in this case, Hide and Display.
"Run-time polymorphism" occurs whenever an object of a class-wide type is
passed to one of the primitive operations -- an automatic dispatch is
performed to the "appropriate" implementation of the primitive operation. In
this example, on each call of Hide and Display with the class-wide parameter
W, an indirect call is made through a dispatch table identified at run-time by
a "type tag" carried with each class-wide object.
The distinction between specific types and class-wide types is a
distinguishing feature of Ada 9X. In Ada 83, user-defined types are always
"specific" types, and when used as a formal parameter type, the actual
parameter must have exactly the same type. In most object-oriented
programming languages, all types in a type hierarchy are "class-wide," and
when used as a formal parameter type, the actual parameter may be of that type
or any of its derivatives. For Ada 9X, we have explicitly distinguished these
two concepts, to provide exact type matching by default, while also supporting
class-wide type matching when explicitly desired.
To summarize the Ada 9X support for object-oriented programming: record and
private types may be extended as part of type derivation to support general
single inheritance; class-wide types provide class-wide type matching, and use
automatic dispatching when passed to a primitive operation to provide run-time
polymorphism.
2.2. Programming in the Large
Ada 83 has been successfully used in the development of very large programs,
including those over a million line of code. However, there can be serious
practical problems, when developing such large systems, associated with small
changes resulting in large amounts of recompilation or relinking, due to the
requirement for strong type checking across separately compiled program units.
Even with a very fast compiler, it may be impractical to recompile or relink
certain subsystems, due to configuration management and strict quality
assurance and testing considerations.
For Ada 9X, we have addressed some of the issues associated with "programming
in the large" by enhancing the separate compilation facilities, as well as
standardizing mechanisms for breaking large applications into separately
linkable "partitions," which can be loaded and elaborated independently from
one another while preserving strong typing.
Ada 83 has excellent separate compilation facilities, enforcing full strong
type-checking across separately compiled units of the application. However,
the namespace for "library units" (the basic independently compilable unit of
an application) is flat. For Ada 9X, we have proposed that library unit names
may form a hierarchy. The program library becomes a forest of library unit
trees, with each "root" library unit named with a single identifier, and
"child" library units named by a sequence of identifiers separated by periods.
As an example of child library units, we show a hypothetical windowing
user-interface subsystem, following up on the object-oriented programming
examples given above:
package Window_System is
-- This package defines the types that form the
-- basis of the window system.
-- Child Library units are used to provide additional
-- types and operations.
type Window_Id is private;
type Pixel_Number is new Integer
subtype Pixel_Count is Pixel_Number range 0..Pixel_Number'LAST;
type Point is -- A point on a two-dimensional screen
record
X, Y : Pixel_Number;
end record;
type Basic_Window is tagged limited private;
-- the "root" of the hierarchy of window types
-- Here are the "primitive" operations of Basic_Window.
-- These "dispatch" automatically when passed
-- a class-wide object (of type Basic_Window'CLASS).
procedure Create_Window(
Win : in out Basic_Window;
Lower_Left : Point;
Upper_right : Point);
procedure Display(Win : in Basic_Window);
procedure Hide(Win : in Basic_Window);
function Id(Win : Basic_Window) return Window_Id;
private
-- Here are the full declarations of the private types.
type Window_Id is new Integer;
type Basic_Window is tagged
record
Id : Window_Id;
Lower_Left : Point;
Upper_Right : Point;
end record;
end Window_System;
package Window_System.Bells_And_Whistles is
-- This "child" library unit defines a type extension
-- of the root window type.
type Fancy_Window is new Basic_Window with private;
procedure Display(FW : in Fancy_Window);
-- The inherited Display primitive
-- operation is being overridden
private
type Fancy_Window is new Basic_Window with
record
. . . (as in earlier example)
end record;
end Window_System.Bells_And_Whistles;
with Window_System.Bells_And_Whistles;
procedure Test is
-- This procedure uses the child Library unit
Win : Window_System.Bells_And_Whistles.Fancy_Window;
begin
...
end Test;
Going along with this hierarchical name space enhancement is the
generalization of the concept that units logically nested within a parent unit
may "see" the private declarations of the parent unit, and thereby effectively
extend the functionality of the private types declared in the parent unit. By
using child library units, the set of operations of a private type may be
broken up into logical groupings, rather than being provided in a single
monolithic package.
The hierarchical name space allows a very large application to be organized
into a set of subsystems, each composed of a tree of library units.
Furthermore, when a subsystem needs to be extended to service additional
clients, one may add child library units rather than edit preexisting library
units, thereby eliminating any disturbance (or recompilation) of existing
clients of the subsystem. Furthermore, by keeping individual library units
smaller and placing logically separable functionality in child library units,
changes to child library units will affect only those clients interested in
that particular part of the subsystems.
In addition to adding flexibility to library unit naming, we have also
proposed to add flexibility to the definition of a "program." In Ada 83, all
of the library units of a program were loaded and elaborated together.
However, for large systems, it is often more appropriate for a conceptual
"program" to actually be composed of independently loaded and elaborated
pieces. For Ada 9X, we have formalized this concept, using the term
"partition" to represent the unit of a system that is loaded and elaborate at
one time, while explicitly allowing such partitions to communicate with other
partitions using shared packages and (remote) subprogram calls. This approach
preserves the benefits of strong type checking, while allowing program
partitions to be loaded and updated incrementally. This can be critical for a
long-running system, as well as for a fault-tolerant system.
In the "core" of the language standard, we proposed to allow programs to be
broken up into independently elaboratable partitions. In an annex devoted to
support for distribution, we propose a set of pragmas to provide a standard
set of capabilities for partitioning programs. In the annex, we define two
kinds of partitions: "passive" partitions, consisting of shared data, but no
thread of control; and "active" partitions, consisting of one or more threads
of control, communicating with other active partitions using remote subprogram
calls and data stored in passive partitions.
2.3. Real-time and Parallel Programming
Ada 83 is one of the few "mainstream" programming languages with support for
multiple threads of control (tasks) incorporated into the language syntax.
Ada also incorporates syntactic support for high-level synchronization between
tasks, based on the "rendezvous" concept. For many application areas, the
synchronous task-to-task communication capability inherent in the rendezvous
has been adequate for building multi-tasking systems. However, in other
application areas, a lower-level or asynchronous communication capability is
required.
Ada 83 does not preclude the provision of efficient synchronous communication
capabilities through the use of implementation-defined packages or specialized
pragmas. However, the fact that only synchronous communication is supported
directly in the language has led to some user dissatisfaction, since the
approaches based on implementation-defined packages or specialized pragmas are
inherently less portable and generally less elegant.
For Ada 9X, we have proposed to provide language support for synchronous
communication by providing a data-oriented synchronization "building block"
called a "protected record," to complement the synchronous task-to-task
communication capability represented by rendezvous.
A protected record is a combination of record components plus "protected
operations," which have exclusive access to the components. A protected
record type is specified by a program unit that defines the components and the
protected operations, that are either read-only "protected functions,"
read/write "protected procedures," or potentially suspending entries
(analogous to task entries).
Here is an example of a "mailbox" protected record type, defined in a generic
package:
generic
type Message_Type is private;
package Mailbox_Pkg is
type Message_Array is array(Positive range <>) of Message_Type;
protected type Mailbox(Size : Natural) is
function Count return Natural;
-- Count of messages in the Mailbox
procedure Discard_All;
-- Discard all messages in the mailbox
entry Put(Message : in Message_Type);
-- Put a message into the mailbox;
-- suspend until there is room
entry Get(Message : out Message_Type);
-- Get a message from the mailbox;
-- suspend until there is a message.
private record
-- Define the components of the protected record:
Contents : Message_Array(1..Size);
-- This array holds the messages
Current_Count : Natural := 0;
-- Count of messages in the mailbox
Put_Index : Positive := 1;
-- Index into array for adding next message
Get_Index : Positive := 1;
-- Index into array for moving next message
end Mailbox;
end Mailbox_pkg;
This generic package may be implemented as follows:
package body Mailbox_Pkg is
protected body Mailbox is
function Count return Natural is
-- Count of messages in the Mailbox
begin
return Current_Count
end Count;
procedure Discard_All is
Discard all messages in the mailbox
begin
count := 0;
-- Reset the array indices as well
Put_Index := 1;
Get_Index := 1;
end Discard_All;
entry Put(Message : in Message_Type) when Count < Size is
-- Put a message into the mailbox.
-- "Count < Size" is the "barrier" for this entry.
-- Any caller is suspended until this is true.
begin
-- Insert new message, bump index (cyclicly)
-- and increment counter
Contents(Put_Index) := Message;
Put_Index := Put_Index mod Size + 1;
Count := Count + 1;
end Put;
entry Get(Message : out Message_Type) when Count > 0 is
-- Get next message from the mailbox.
-- "Count > 0" is the "barrier" for this entry.
-- Any caller is suspended until this is true.
begin
-- Get next message, bump index (cyclicly)
-- and decrement counter
Message := Contents(Get_Index);
Get_Index := Get_Index mod Size + 1;
Count := Count - 1;
end Get;
end Mailbox;
end mailbox_Pkg;
As illustrated above, each protected operation specified in the protected type
definition must have a body provided in the protected body. Furthermore, each
entry body must have an "entry barrier" specified after the reserved word
"when." Any caller of any entry is automatically suspended if the entry
barrier is false, on an entry queue associated with the entry.
Upon completion of a protected procedure or entry, the components of the
protected may have changed, so the entry barriers are rechecked to see if one
of them has become true. If so, the first caller on the associated entry
queue is selected and the entry body is executed for the caller. This process
of "servicing the entry queues" continues until there are no more callers on
entries with true barriers.
To use the generic package from the above example, one instantiates it with
some message type, and then declares an instance of the Mailbox type.
Protected operations are performed by using a subprogram call syntax, but with
the protected record object identified by a prefix to the operation name.
This is illustrated in the following example:
with Text_IO, Mailbox_Pkg;
procedure Test is
type Line is record
-- The type to be used for messages
Length : Natural := 0;
Data : String(1..80);
end record;
package Line_Buffer_Pkg is
new Mailbox_Pkg(Message_Type => Line);
Line_Buffer : Line_Buffer_Pkg.Mailbox(Siz => 20);
-- Instance of mailbox with room for 20 messages
task Producer; -- Task that will put messages into mailbox
task body Producer is
L : Line;
begin
for I in 1..100 loop
Text_IO.Get_Line(L.Data, L.Length)
-- Read a line from Standard_Input
Line_Buffer.Put(L); -- Entry call to put message
end loop;
end Producer;
task Consumer; -- Task that will get message out of mailbox
task body Consumer is
L : Line;
C : Natural;
begin
for I in 1..100 loop
Line_Buffer.Get(L); -- Entry call to get message
Text_IO.Put_Line(L.Data(1..L.Length));
-- Write the line to Standard_Output
-- Check if Consumer is falling way behind Producer
C := Line_Buffer.Count(L); -- Protected func call
if C > Line_Buffer.Size/2 then
-- Report that Consumer is falling way behind
Text_IO.Put_Line("****Buffer count now =" &
Integer'IMAGE(C));
end if;
end loop;
end Consumer;
begin
null; -- Wait for tasks to complete
end Test;
Entry calls on protected record entries may be used anywhere (task) entry
calls are permitted in Ada 83, in particular in conditional and timed entry
call statements.
Protected records, with their support for efficient mutual exclusion and
asynchronous signaling via entry barriers, are the most important addition to
Ada 9X for real-time and parallel programming. In addition, we have proposed
other enhancements, including a more general form of selective entry call, and
a requeue capability so that a server can examine the parameters of an entry
call before committing to servicing the call. Finally, a real-time "annex"
has been proposed where standardized packages and pragmas are defined that
will provide dynamic priority control, a "monotonic" real-time clock, and a
CPU time accounting capability.
3. Summary
The capabilities of Ada 83 are being enhanced through the definition of a
small number of new "building blocks" in three basic areas, object-oriented
programming, programming in the large and real-time and parallel programming.
In each case, we have used existing features as the basic for the enhanced
capabilities: Derived and universal types provide the basis for object-
oriented programming; the existing library unit concept forms the basis for
the hierarchical name space and program partitioning; and the concepts of
private types, functions, procedures, and entries form the basis for the
protected record construct, supporting fast mutual exclusion and asynchronous
task communication.
Revising a standard language is always a difficult task, with a tension
between the goal of appealing to new users and supporting new and challenging
application areas, and the goal of minimizing disruption to existing users and
existing applications. We believe that the proposals for Ada 9X represent a
natural evolution of the existing excellent Ada 83 capabilities, while
ensuring that Ada can be used efficiently and productively to solve the
complex systems implementation problems of the 90s.
**********************
Reprinted with permission.
Ada Information Clearinghouse (AdaIC)
P.O. Box 46593
Washington, DC 20050-6593
703/685-1477, 800/AdaIC-11, FAX 703/685-7019
adainfo@ajpo.sei.cmu.edu; CompuServe 70312,3303
The AdaIC is sponsored by the Ada Joint Program Office and operated by IIT
Research Institute.