From: maajs@levels.unisa.edu.au
Newsgroups: unisa.cis.ada
Subject: Tutorial solutions for week 9 (10?)
Date: 19 Nov 92 12:54:40 +1030
Organization: University of South Australia

Programming in Ada,   Tutorial solutions for week 9.


1.
Ada declaration for type colours:

        type colours is (red, green, blue, cyan, magenta, yellow, black, white);

A subtype is a declared by placing a (optional) constraint on an existing type
(the parent type).  Variables of the subtype are compatible with the parent
type.  The subtype simply places a constraint on the range of values of valid
values for a variable of the subtype.  For example:

        subtype primary_colours is colours range red .. blue;

declares a subtype primary_colours where the only valid values are  red, green
and blue.  With variable declarations

        c1 : colours := red;
        c2 : primary_colours := green;

we could make the assignment

        c2 := c1;

and
        c1 := c2;

however the assignment

        c2 := cyan;

would cause a constraint_error to be raised as cyan is outside the valid range
of values for c2.

A derived type is declared by placing an (optional) constraint on an existing
type, but declaring it as a new type.  For example:

        type tints is new colours range red .. yellow;

This declaration creates a new type tints derived from colours but which is
incompatible with the type colours.   This declaration also creates overloadings
for the enumeration values red to yellow. If we declare variables

        c1 : colours := red;
        c2 : tints := green;

then attempts to assign c1 to c2 or vice versa will result in compilation errors
as the two types are incompatible and cannot be mixed.

In summary,  derived types create a new type which is not compatible with the
parent type while subtypes do not create a new type, but simply place an additional
constraint on values of the parent type.


2.
Discuss the meaning and usage of the with and use declarations in an Ada program.

Ada programs normally consist of a number of program units, with one of the
program units being the `main program'.  The dependencies between the program
units is specified by use of with declarations.  If a program unit needs to
use resources (such as types, procedures, functions, constants, or variables)
from another program unit, it must `with' the unit.  For example, suppose a
stand alone procedure test needs to use procedures from package text_io,
then the procedure declaration must be preceed by a with declaration:

        with text_io;
        procedure test is
          ...

Now the objects declared in text_io can be used within the procedure test using
a dot notation, such as:

        text_io.new_line;

A program unit can `with' any number of other program units.

The `with' declaration does not make the objects in a program unit directly
visible,  and this can make usage, particularly of types, cumbersome.  For
example,  if a package example contains a declaration of a derived type:

        type count is new positive range 1 .. 1000;

and a procedure test with's the package example and declares a variable val
of type example.count.  Now a simple test such as

        if (val = 1) then
            ...

would have to be expressed as

        if example."="(val,1)

as the operator example."=" is not directly visible.  One way of making the
operator (and all other objects in the package example) directly visible is
via the declaration 'use example;'.  This can only be used if the package is
visible (which usually done via a `with' declaration), and often follows just
after a with declaration.  For example:

        with example;
        use example;
        procedure test is
          ...
However, excessive use of the the `use' declaration can cause the number of
directly visible objects to be very high,   reducing the readability and maintainability
of the code.   In addition,  it may cause unexpected overloadings of objects,
which can lead to incorrect code.  In general,  the number of packages in the
`use' declarations should be kept to a minimum,  with one or two being reasonable.

3.
Private and limited privage types in Ada have restrictions on where they are
declared,   and impose restrictions on the usage of variables of these types.
  Unlike non-private types,  private and limited private types can only be
declared in package specifications.   These types are declared as private or
limited private,   and the declarations are completed in the private part of
a package declaration.  For example:

        package demo is
            type a is private;
            type b is limited private;
            ...
        private
            type a is range 1..10;
            type b is record
                    real, imaginary : float;
                            end record;
        end demo;

Private types are intended to be used to declare abstract data types where
the valid operations on values of the type are specified in the package where
the type is declared.   The Ada language then imposes restrictions on the usage
of the objects so that the abstraction being implemented by the type is not
violated.  The main restrictions imposed are that:

a)
The details of the data structure implemented by objects of a private or limited
private type are not accessible to code outside of the package in which the
type is declared and implemented.

b)
Operations on private types are restricted to assignment and test for equality.

c)
Neither of these operations are available for limited private types.

The lack of the assingment operation for limited private types allows a data
structure which is implemented using an array to be changed to use pointers
without changing the semantics of the assignment operator (as the operator
is not available).  If the assignment operator was available the assignment
of one variable to another would change from making a copy of the variable
to making an alias for a pointer variable.
The requirement for a private type to be completed in the private part of a
package can result in the need to recompile both the specification and the
implentation packages if the data structure is changed.  This can be avoided
by making the type a pointer to a type which is completed in the package body.

4.
Type declarations:

        type tree_node;
        type tree is access tree_node;
        type tree_node is record
                        data : integer;
                        count : natural;
                        left, right : tree;
                          end record;

Note that the record type tree_node must be declared before a pointer to it,
 so an incomplete type declaration is required.
The code for the procedure add is:

        procedure add(the_data      : in        integer;
                     to_the_tree : in out tree) is
        begin
            if the_data = to_the_tree.data then
                to_the_tree.count := to_the_tree.count + 1;
            elsif the_data < to_the_tree.data then
                add(the_data, to_the_tree.left);
            else
                add(the_data, to_the_tree.right);
            end if;
        exception
            when constraint_error =>
                to_the_tree := new tree_node'(the_data, 1, null, null);
        end add;

Note that when to_the_tree is null,  an attemp to access a component of the
record `pointed' to by to_the_tree will result in a constraint_error exception
being raised.  This exception is handled by creating a tree_node with the appropriate
values in it and assigning a pointer to it to to_the_tree.

Newsgroups: comp.os.os2.misc