Previous | Next | Table of Contents | Index | Program List | Copyright

Appendix I. Ada Hints for Pascal Users

Ada is a language that is, in many respects, similar to Pascal. However, it is not a "superset" of Pascal. The statement syntax is slightly different (simpler, in the opinion of many), and many familiar Pascal features are implemented somewhat differently. As a learning aid to those experienced in Pascal but new to Ada, this appendix summarizes areas in which the languages differ enough to cause some difficulty in the form of compilation errors.

The most important difference between Ada and Pascal is that the strong Ada standard, coupled with the compiler validation process, ensure that the same Ada language is accepted by all compilers. Syntactic extensions, such as are found in most useful Pascal systems, do not occur in Ada. On the other hand, the Ada language defined by the standard covers nearly all the features of the Pascal extensions.

Declarations and Declaration Order

The Pascal standard requires a rigid declaration order (constants, types, variables, subprograms) that is relaxed by some implementations. Ada declaration order is somewhat more flexible. The Ada standard refers to "basic declarative items" and "later declarative items." Among the former are declarations of constants, types, and variables; among the latter are functions and procedures. (Other declarations are beyond the scope of this book.) In the declarative part of a program or subprogram, basic declarative items can be freely intermixed--with the understanding, of course, that everything must be declared before it is referenced. All basic items must precede all later items; put simply, subprogram declarations must follow the others.

In Pascal, the words TYPE, CONST, and VAR appear only once in a declarative section. In Ada, each type or subtype declaration must be opened by TYPE or SUBTYPE, respectively. A constant is declared as, for example,

    FirstLetter: CONSTANT Character := 'A';
and the reserved word VAR is not used at all; a variable is simply declared as, for example,
    Sum : Integer;
A record type declaration must be closed by END RECORD.

Control Structures

All control structures are fully bracketed in Ada, including IF-END IF, LOOP-END LOOP, CASE-END CASE. Further, a semicolon terminates a statement--it does not separate statements, as in Pascal. This yields a syntax that is easier to use correctly than Pascal's. For example, the Pascal statement

    IF X < Y THEN
      A := B;
is written in Ada as
    IF X < Y THEN
      A := B;
    END IF;
and the Pascal statement
    IF X < Y THEN
      BEGIN
        A := B;
        Z := X
      END
    ELSE
      BEGIN
        A := X;
        Z := B
      END;
is written in Ada as
    IF X < Y THEN
      A := B;
      Z := X;
    ELSE
      A := X;
      Z := B;
    END IF;
The fully-bracketed syntax ensures that a "dangling ELSE" cannot be written.

FOR loop control variables are declared implicitly; this is the only exception to the rule that everything must be explicitly declared. A FOR counter is local to the loop body. Declaring the loop counter as a variable, as in Pascal, does no real harm, but it declares a different variable, which is then hidden by the actual loop counter and therefore not visible in the loop body.

FOR loop ranges are often stated as type or subtype names, as in

    FOR Count IN IndexRange LOOP
Ada has no REPEAT loop structure; instead, use LOOP-END LOOP with an EXIT WHEN clause at the bottom of the loop.

The choice variable in a CASE statement must be of a discrete (integer or enumeration) type; the various CASE choices must cover, in a nonoverlapping fashion, all possible values of the choice variable.

Types and Data Structures

Two-dimensional arrays are not arrays of arrays. Therefore, A(J)(K) is not the same as A(J,K): The former indeed refers to an array of arrays, the latter to a two-dimensional array. One reason these are different structures in Ada is that the standard does not specify the storage mapping (row- or column-major) for multidimensional arrays. This allows a clever implementer to use a nonlinear mapping, for example. In practice, most current Ada compilers use a row-major mapping, in keeping with Pascal and C rules.

The type of a record field must always be a type name; it cannot be an anonymous type such as ARRAY or RECORD. To build hierarchical record types, build the lower-level ones first, then use their names as fields in the higher-level ones.

There is nothing in Ada that corresponds to Pascal's WITH. All record and array references must always be fully qualified.

Variant records are much more tightly controlled in Ada than in Pascal. It is not possible to write a "free union," or variant record without a discriminant (tag field). In Pascal and C, free unions are frequently used to evade type checking, but cannot be used for this purpose in Ada. (Ada has a generic function called Unchecked_Conversion that indeed is used to evade type checking, but use of this is beyond the scope of this book).

There is no SET type in Ada. A package giving the equivalent functionality is presented in full as Programs 11.14 and 11.15.

Type and Subtype Compatibility

This matter is discussed at length throughout the book. The most important thing to remember is that Ada uses named type equivalence, not structural equivalence. For example, given the declarations

    A, B: ARRAY(1..10) OF Float;
    C   : ARRAY(1..10) OF Float;
the array assignment statements
    A := B;
    C := B;
are both invalid, because each of the three arrays has a different anonymous type, assigned by the compiler. (Some Pascal compilers would allow the first assignment.) To allow the array assignments, one must give a type name:
    TYPE List IS ARRAY(1..10) OF Float;
    A, B: List;
    C: List;
Both assignments are now valid. The Pascal style of using anonymous types is not used in this book, and we recommend against it.

Subprogram Parameters

Ada's parameter modes IN, OUT, and IN OUT are only roughly equivalent to the value and VAR parameters of Pascal.

Within the body of a subprogram, IN parameters can only be read, never written. The main difference between OUT and IN OUT parameters is that the current value of an actual IN OUT parameter is passed to the procedure, whereas, in general, the value of an actual OUT parameter is not passed, and can therefore assume to be undefined until given a value by the subprogram. Functions cannot have OUT or IN OUT parameters.

There is no efficiency to be gained by passing as IN OUT an array to be used as an IN parameter. This is common in Pascal, where large arrays are usually passed as VAR parameters. Pascal requires VAR parameters to be passed by reference and value parameters to be copied. The rules in Ada are different: Scalar parameters are always passed by value/result, whatever their mode. Ada permits composite (array and record) parameters to be passed by value/result, but compilers almost never do this, especially if the composites are large. Practical compilers pass arrays and large records by reference even if they are IN; since IN parameters cannot be written, there is no danger of changing their value in the calling program.

In the case of scalar OUT and IN OUT parameters, the values are copied back to the calling program at normal completion of the procedure call. That is, if the procedure call completes by propagating an exception to the caller, the parameter values are not copied back and therefore the caller still has theoriginal values.

The input/output statements in Ada are ordinary procedure calls, which means that only a single integer, float, character, string, or enumeration value can be read or displayed with each call of Get or Put. One cannot supply an arbitrary number of parameters to input/output statements, as one would do in Pascal. Doing so will surely result in compilation errors of the form "unmatched procedure call," when the compiler searches for a Get or Put whose expected parameters match the supplied ones.

Packages and their Relation to Units

Units are not a part of the ISO Pascal standard, but are provided by many extended Pascal systems, including Borland's Turbo and Symantec's Think series. Units are a rough equivalent of Ada packages, with two important differences:

The Use of IS and the Semicolon

Endless grief awaits Ada users who confuse the use of the semicolon with the use of IS; with some compilers, this leads to long sequences of propagation error messages. The worst offense is using a semicolon instead of IS in a subprogram declaration, as one would do in Pascal.

    PROCEDURE DoSomething(X : Integer); ---- <---- this means TROUBLE!
      
      -- declarations
    
    BEGIN
      
      -- statements
    
    END DoSomething;
The problem is that it is legal to use the semicolon, but the meaning is not what you expect. The line
    PROCEDURE DoSomething(X : Integer);
is not a declaration, but a procedure specification, similar to a Pascal FORWARD specification. Confusing the semicolon with the IS is therefore almost guaranteed to lead to a large number of propagation errors from the compiler: Since the Ada parser treats the statement as a specification, it is confused by the declarations and BEGIN-END block that follow, which seem to be out of context and not well-formed. IS is precisely the way that Ada knows a procedure body is expected next; the user forgets this at his or her peril.

Subprogram specifications appear as a part of package specifications, and can also be useful in contexts where a Pascal FORWARD would be written. In the latter case, the first line of the body must be identical to the specification, except for replacing the semicolon by IS. This is different from Pascal, where the parameter list is not repeated.


Previous | Next | Table of Contents | Index | Program List | Copyright

Copyright © 1996 by Addison-Wesley Publishing Company, Inc.