Augustana University College

COMPUTING SCIENCE 370
Programming Languages


Ada



Modularity and Abstraction

Problem: The software crisis.

Solution: Break large programs into small independent modules.

Question: How is independent modularization achieved?

Answer: Information hiding (Parnas)

Data Abstraction

Functional Abstraction

Characteristics of Fourth-Generation Programming Languages

Syntactic Structure

Ada's syntax, like that of most fourth-generation programming languages, is:

  1. in the Algol/Pascal tradition
    E.g.,
       procedure <name> (<formal parameters>) is
          <local declarations>
       begin
          <statements>
       end <name>;
    

    but

  2. fully bracketed
    E.g.,
       loop . . . end loop
       if . . . end if
       case . . . end case
       record . . . end record
       package <name> is . . . end <name>
    

Structural Organization

Data Structures

Name Structures

Bindings

A name can be bound to:

Declarations

Problems with name structures in block-structured languages

(Wulf and Shaw, 1973)

Side effects
Changes in the non-local environment resulting from hidden access to (a) variable(s).
E.g.,
   function max ( x, y : integer );
      begin
         count := count + 1;    { side effect }
         if x > y then
            max := x
         else
            max := y
      end;

Indiscriminate access
The inability to block access to variables which should be private.
E.g.,

Indiscriminate access

Vulnerability
The inability of a program segment to preserve access to a variable.
E.g.,

Vulnerability

No overlapping definitions
There is no control over shared access to variables.
E.g., given three modules P1, P2, and P3 such that the language should provide a mechanism like

Overlapping definitions

but in a block-structured language, access must be like

No overlapping definitions


PARNAS'S INFORMATION HIDING PRINCIPLES
The language should permit modules to be designed such that
  1. the user has all the information needed to use the module correctly, and nothing more;
  2. the implementor has all the information needed to implement the module correctly, and nothing more.

Packages

Ada uses packages to implement information hiding.

Generic Packages

To have several instances of the same ADT, we use a generic package.
E.g.,

   generic package Stack is
      . . .
   end Stack;

Control Structures

Ada has seven classes of control structures, most of them fully bracketed:

  1. Conditionals
  2. Iterators
  3. Case
  4. Subprograms
  5. goto
  6. Exception handling
  7. Concurrency

Conditionals

   if <boolean expr> then
      <statements>
   end if;

   if <boolean expr> then
      <statements>
   else
      <statements>
   end if;

   if <boolean expr> then
      <statements>
   elsif <boolean expr> then
      <statements>
   . . .
   else
      <statements>
   end if;

Iterators

Case

   case Value is
      when Value1 | Value2 =>
         <statements>
      when Value3 =>
         <statements>
      when Value4 | Value5 | Value6 =>
         null;
      when others
         <statements>
   end case;

Subprograms

Ada provides explicit support for three parameter modes:

Ada also supports position-independent parameters with default values.
E.g.,

   procedure Draw_Axes
      ( X_Origin, Y_Origin : Coordinate := 0;
        X_Scale, Y_Scale : Real := 1.0;
        X_Spacing, Y_Spacing : Natural := 1;
        X_Label, Y_Label : Boolean := True;
        X_Log, Y_Log : Boolean := False;
        Full_Grid : Boolean := False );
   Draw_Axes ( 500, 500, Y_Scale => 0.5, Y_Log => True,
               X_Spacing => 10, Y_Spacing => 10 );

Position-independent parameters are an example of the Labelling Principle.

Default parameters are an example of the Localized Cost Principle, because they allow users to ignore options (parameters) which they do not require.

However, costs are associated with these features, as they are with all features:

Goto

EXERCISE: Was goto necessary, given that exit is provided?

Exception Handling

Exception handler
A block of code to be executed when an exception is raised (signalled).

E.g.,

   procedure Producer ( . . . );
      use Stack;
   begin
      . . . 
      Push ( Data );  -- If an exception is raised here
                      -- (by attempting to push to a full stack),
                      -- execution jumps to ***
      . . .
   exception
      when Stack_Error =>
         declare
            Scratch : Integer;
         begin        -- *** exception handler
            for I in 1 .. 3
            loop
               if not Empty () then
                  Pop ( Scratch );
               end if;
            end loop;
            Push ( Data );
         end;
   end Producer;

Exceptions propagate from callee to caller until an exeption handler is found:

This means that exception handlers use dynamic scoping.

Why dynamic scoping?
Different callers may want to take different actions.

In implementation, an exception is like a dynamically scoped, non-local goto:

Thus, exceptions violate both the Structure Principle and the Regularity Principle.

Concurrency

A tasking facility allows a program to do more than one thing at a time.
E.g., a word processor that allows the user to edit one file while printing another:

   procedure Word_Processor is

      task Edit;
      end Edit;

      task body Edit is
      begin
         -- edit some file   
      end Edit;

      task Print;
      end Print;

      task body Print is
      begin
         -- print some file   
      end Print;

   begin
      -- initiate tasks and wait for their completion
   end Word_Processor;

In general, there are three common means of synchronizing communication between concurrent processes:

Ada uses rendezvous:

E.g., a system which retrieves records to produce a summary, such that records may be retrieved concurrently with the production of the summary:

   procedure DB_System is

      task Summary;
      end Summary;

      task body Summary is
      begin
         . . .
         Seek ( ID );
         . . .
         Fetch ( New_Record );
         . . .
      end Summary;

      task Retrieve;
         entry Seek ( K : Key );
         entry Fetch ( out P : Packet );
      end Retrieve;

      task body Retrieve is
      begin
         loop
            accept Seek ( K : Key ) do
               Save_Key := K;
            end Seek;

            -- seek packet record and put it in New_Packet
            . . . 

            accept Fetch ( out P : Packet ) do
               P := New_Packet;
            end Fetch;
         end loop;
      end Retrieve;

   begin
      -- initiate tasks and wait for their completion
   end DB_System;

Note that the Fetch message is sent from the task Summary to the task Retrieve, even though the data transfer of the record retrieved from the database is from Retrieve to Summary, because the mode of the Fetch message parameter is out -- when it receives a Fetch message, Retrieve copies the record it retrieved from the database into the out-mode parameter provided by Summary.

Comparison of Subprograms and Tasks
Subprogram Task
Parameters transmitted from caller to callee. same
Caller is suspended and callee is activated. Caller continues executing concurrently with callee.
When callee is deactivated, caller is reactivated. Caller may not terminate until all local tasks finish.

Ada provides a special synchronization control structure to allow a task to wait for any of several rendezvous.
E.g.,

   select
      accept Send ( D : Document ) 
      do
         -- print the document
         . . .
      end Send;
   or accept Terminate 
      do 
         exit
      end Terminate;
   end select;

A deadlock can occur if one task is waiting for a rendezvous which never takes place. One way to avoid deadlocks is to use guarded entries so that a message is accepted only if a condition is satisfied:

   select
      when Avail < Size accept Send ( D : in Document ) 
      do
         -- add document to buffer
         Avail := Avail + 1;
      end Send;

   or when Avail > 0 accept Receive ( D : out Document )
      do
         -- return a document from the buffer
         Avail := Avail - 1;
      end Receive;

   or accept Terminate 
      do 
         exit
      end Terminate;
   end select;

Copyright © 2000, 2001 Jonathan Mohr