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.



