Now that we have very brief flavor of what Ada code looks like, we need to define some key terms.

More formally, an Ada program is composed of one or more program units. A program unit can be a:

  1. subprogram, which define executable algorithms. Procedures and functions are both subprograms.
  2. package, which defines a collection of entities. Packages are the main grouping mechanism in Ada, somewhat analogous to Modula's "module".
  3. task unit, which defines a computation that can occur in parallel with other computations.
  4. protected unit, which can coordinate data sharing between parallel computation. This did not exist in Ada 83.
  5. generic units, which helps to make reusable components (C++'s templates are similar).

The latter three are advanced topics, so we will concentrate for now on packages and subprograms.

The package is structurally the most important kind of program unit. Most Ada programs are basically a set of a large number of packages, with one procedure used as the ``main'' procedure to start the Ada program.

In section 1-1 we defined a simple procedure called Hello. What kind of program unit was procedure Hello? Subprogram Package Task Unit Right. A procedure is a kind of subprogram, and a subprogram is a kind of program unit. No, sorry. While packages are very important to Ada, procedure Hello was not a package. No, sorry.

Program units (including subprograms and packages) normally consist of two parts:
  • The declaration, which contains information that will be visible to other program units. The declaration defines the interface for a program unit. Sometimes people refer to a declaration as a specification. They are somewhat analogous to the contents of C ``.h'' files.
  • The body, which contains implementation details that need not be visible to other parts. They are somewhat analogous to the contents of C ``.c'' files.

These separate parts of program units are usually stored in separate files. This explicit distinction between declaration and body allows a program to be designed, written, and tested as a set of largely independent software components.

There are two special cases to help make programming easier:

  1. Separate declarations are not required for subprograms (procedures and functions). If a subprogram has a body but no declaration, the body of a subprogram can serve as its own declaration. This makes writing the `hello, world' program in lesson 1 easier - technically, that simple program is a procedure body that automatically gives its own declaration.
  2. For some packages, it's not possible to have implementation details. For example, a package declaration could be just a collection of constants (like pi and the square root of 2). In this case, the package must not have a body, since one isn't needed. This is relatively rare - most packages need both a declaration and a body.

Which part of a program unit contains the implementation details? Declaration Body No, sorry. Right. That was an easy question, but the distinction is important.

The package is Ada's basic unit for defining a collection of logically related entities. For example, a package can be used to define a set of type declarations and their associated operations.

For example, all Ada compilers provide a package called Text_IO. Here's a highly simplified version of the package declaration of the package Text_IO (the lengthy complete definition is part of the RM's appendix A):

package Text_IO is
  type File_Type is limited private;
  type File_Mode is (In_File, Out_File, Append_File);
  procedure Create (File : in out File_Type;
                    Mode : in File_Mode := Out_File;
                    Name : in String := "");
  procedure Close (File : in out File_Type);
  procedure Put_Line (File : in File_Type; Item : in String);
  procedure Put_Line (Item : in String);
end Text_IO;  

The package declaration of package Text_IO defines a type called `File_Type' that represents an opened or created file. The phrase `limited private' means that there are no predefined operations on this type (more about that later).

Package Text_IO also defines a type called `File_Mode'; values of this type can only have one of three values (this is how enumeration types are defined in Ada).

The type definitions are followed by a set of subprograms that can accept values of type File_Type. Note that procedures (subprograms) can be contained inside packages. Procedure `Create' lets you create files with given names; procedure `Close' closes a file.

There are two procedures named `Put_Line' which write text out, but they differ in the arguments they can accept. The first takes a file and the string to be output, while the other just takes the string to be output.

If a package declaration includes other declarations inside it then there must be a package body somewhere that includes the bodies of the items declared. This simplified package declaration for Text_IO has procedure declarations, so somewhere else there must be a package body for Text_IO. In this simplified package declaration for package Text_IO, how many subprograms have been defined that explicitly require a File_Type parameter? One Two Three Four Right. They are Create, Close, and one of the Put_Line procedures. No, sorry. Keep looking. No, sorry. Keep looking. This package does have explicit definitions of four subprograms, but not all of them have File_Type as a parameter. Please look again.

Now that we know about program units, packages, and the difference between declarations and bodies, we can talk about compilation units.

A compilation unit contains either the declaration or the body of a program unit, preceded by the necessary context clause (`with' or `use' clauses). Thus a compilation unit can be a package declaration, a package body, a subprogram declaration, or a subprogram body along with its context clause.

An Ada compiler only compiles collections of one or more compilation units. That's why it's important to understand compilation units - to compile something, it must be a part of a legal compilation unit.

Here's a simplified BNF syntax for a compilation unit. BNF is a common method for describing the syntax of a computer language. If you're not familiar with it, you can read about it in the appendix. The full definition is in section 10.1 of the RM:

  1. compilation_unit ::= context_clause library_item
  2. context_clause ::= {context_item}
  3. context_item ::= with_clause | use_clause
  4. with_clause ::= "with" library_unit_name { "," library_unit_name} ";"
  5. use_clause ::= "use" library_unit_name { "," library_unit_name} ";"
  6. library_item ::= package_declaration | package_body | subprogram_declaration | subprogram_body

Note that compilation units start with "with" and "use" clauses, followed by a program unit declaration or body. We've already seen three compilation units - the simplified package declaration for Text_IO and two versions of the "Hello" program (in two different forms). Let's go back and look at the "Hello2" program to see that it really is a valid compilation unit:

Ada compilers will only compile a compilation_unit, and according to the BNF definition above a compilation_unit is a context_clause followed by a library_item. The BNF also says that a context_clause is a set of zero or more context_items, and a context_item is either a "with" clause or "use" clause. Since Hello2 starts off with a "with" clause and a "use" clause, we have two context_items that make up the context_clause. I haven't shown the definition of a library_item, but it turns out that the rest of Hello2 is a valid library_item, so we have a valid compilation unit.

Although most Ada compilers permit multiple compilation units in a single file, it's usually better to put separate compilation units in separate files. One Ada compiler (GNAT) requires different compilation units to be in different files.

Informally, when people say `show me X's package declaration' they really mean `show me the compilation unit that includes the package declaration of package X'. Which of the following cannot be part of a compilation unit after the context clause? A package declaration A procedure declaration A procedure body A type definition Right. Okay, this question was a little sneaky since we haven't really discussed type definitions yet, but they clearly aren't listed in the BNF defining compilation units and the others are part of the BNF. To compile type definitions you must put them in something else (such as a package declaration); we'll discuss that more later. No, sorry. No, sorry. No, sorry.

Let's briefly review what we've learned so far:
  1. Logically, Ada programs are composed of a set of program units.
  2. There are different kinds of program units; the ones we've concentrated on are subprograms and packages.
  3. Subprograms define processing algorithms. Subprograms can be procedures or functions.
  4. Packages are the main Ada structuring tool used to group things together.
  5. In general, a program unit has two parts, a declaration and a body. Sometimes a declaration is also called a specification.
  6. Ada compilers compile compilation units. A compilation unit is either a program unit's declaration or body, preceded by a context clause.
  7. A context clause is a set of with clauses (that state what other program units are needed) and/or use clauses (the program units to search by default).
Given what you know now, is it possible for an Ada compiler to compile a package declaration (when preceded by the appropriate context clauses), even if implementation details are needed and the package body has not been developed yet? Yes No Right. A package declaration, when preceded by the appropriate context clauses, is a compilation unit and thus can be compiled. The Ada compiler cannot create an executable program from just the declaration alone, but it can check for interface errors.

This makes it easier for teams to develop software - they can develop the declarations and compile them to check their accuracy. Then each of them can go off and develop the bodies for different declarations, with an increased confidence that the different parts will work together. No, sorry. Here are some hints:

  1. If a package declaration has the right context clause in front of it, what does it become?
  2. What does an Ada compiler compile?