home *** CD-ROM | disk | FTP | other *** search
-
-
-
- Chapter 15
- PACKAGES
-
-
- PACKAGES ARE WHY ADA EXISTS
- _________________________________________________________________
-
- One of the biggest advantages of Ada, over most other programming
- languages, is its well defined system of modularization and
- separate compilation. Even though Ada allows separate compilation,
- it maintains the strong type checking among the various
- compilations by enforcing rules of compilation order and
- compatibility checking. Ada uses separate compilation, but
- FORTRAN, as a classic example, uses independent compilation, in
- which the various parts are compiled with no knowledge of the other
- compilation units with which they will be combined. As we progress
- through this material, and additional material to come later, do
- not be discouraged if you find many things to keep in mind when
- doing separate compilations. The rules are not meant to be
- roadblocks, but are actually benefits for you when you are working
- on a large complex system.
-
-
-
- LET'S LOOK AT A PACKAGE
- _________________________________________________________________
-
- Examine the file named ADDERPKG.ADA for our ================
- first example of a separately compiled Ada ADDERPKG.ADA
- package. A package, as the term is used in Ada, ================
- refers to a collection of related entities, the
- collection being composed of procedures,
- functions, variables, constants, types, subtypes, and even other
- packages. In our present example, the package is composed of one
- type, and one procedure.
-
-
-
- THE SPECIFICATION OF THE PACKAGE
- _________________________________________________________________
-
- Lines 4 through 8 define the specification of the package named
- AdderPkg, which is actually a very simple package, and purposely
- kept simple for illustrative purposes. The type MY_ARRAY is
- defined, as well as the procedure heading for Add_Em_Up in the
- specification part of the package. The only things a user needs
- to know about the package in order to use it are defined in the
- package specification, so it becomes the interface to the outside
- world. With a few defining statements, this is all the user would
- need to know about the package, and he could be kept away from the
- actual details of how the procedure does its job. We will see more
- about the topic of information hiding later in this chapter.
-
-
- Page 15-1
-
- Chapter 15 - Packages
-
- Note that anything that is declared in the specification part of
- the package can be used in any other package that with's this
- package.
-
- We have an unconstrained array type declared in line 5 which we
- have not yet studied in this tutorial. The range for the subscript
- is defined by the "<>", which is a box that must be filled in later
- when we define the actual type. We will cover this in detail in
- the chapter on advanced array topics.
-
-
-
- THE BODY OF THE PACKAGE
- _________________________________________________________________
-
- Lines 12 through 23 give the body of the package, and it is
- distinguished from the specification by the reserved word body in
- its header, and by the fact that the procedure is completely
- defined here. Anything defined or declared in the specification
- part of the package is available for use here, just as if it were
- defined at the beginning of this section. The procedure header is
- redefined here in full, and it must exactly match the definition
- in the specification or you will get a compile error and no
- compilation. There is nothing different about this procedure from
- any other procedure we have seen, it just happens to be in the
- package body.
-
- Note that any types, variables, constants, procedures, or
- functions, can be declared in the package body for use within the
- body, but none of them are available outside of the package because
- they are not defined in the specification part of the package. The
- variable declared in line 15 named Total is not available outside
- of this package and there is no way it can be referred to outside
- of the package without being declared in the package specification.
- In fact, since it is embedded within the procedure, it would be
- hidden anyway, but the fact remains that no entities are available
- outside of the package except those that are declared in the
- specification of the package.
-
- Note that since the array has no defined limits, we must use
- attributes to define the loop range. Even though you may find this
- a bit confusing, you will appreciate the flexibility found here
- after we study some of the more advanced topics.
-
-
-
- IT CAN BE COMPILED BUT NOT EXECUTED
- _________________________________________________________________
-
- This file can be compiled, but it cannot be linked and executed
- because it is not a complete program, it is only a package
- containing a type and a procedure which can be called from another
- program just like we have been calling the procedure Put in the
- Text_IO package throughout this tutorial.
-
- Page 15-2
-
- Chapter 15 - Packages
-
-
- One other point must be made before we look at a program to use
- this package, the specification and the body do not need to be in
- the same file, they can be contained in separate files and compiled
- separately. If this is the case, the specification must be
- compiled prior to compiling the body because the body uses
- information generated during compilation of the specification.
- Actually, even though they are in one file in this example, they
- are considered separately by the compiler, being compiled in serial
- fashion. This file is said to be composed of two compilation
- units.
-
-
-
- FILENAME VERSUS PACKAGE NAME
- _________________________________________________________________
-
- In all of the example programs so far in this tutorial we have used
- the same name for the filename and the program name, or the
- procedure name. This is not really necessary, but it was felt that
- an additional level of complexity should be delayed until later.
- We have arrived at the time when an explanation is needed. When
- Ada compiles a program, it adds the result of the compilation into
- its library using the program name. This library entry includes
- all information needed to link the program later with the other
- needed library entries. Later when you use the linker supplied
- with your compiler, the linker will collect all of the necessary
- compiled packages and subprograms and combine them into an
- executable program.
-
- In order to compile a program, it is necessary to give the filename
- so the operating system can find the program for the Ada compiler,
- but in order to link a program, the filename is no longer of any
- use because the name that really matters is the program name, and
- the program name is what the linker uses. Ada allows identifiers
- to be of any arbitrary length, but your operating system has some
- length limit, eight if you are using MS_DOS, therefore the Ada
- compiler may need to somehow make up a new name if intermediate
- results are put into individual files. It will be up to you to
- determine how your compiler stores intermediate results and how it
- makes up filenames for these results.
-
- For simplicity, therefore, all program names have been limited to
- eight characters, and the same name is used for the filename
- throughout most of this tutorial.
-
-
-
- NOW TO USE THE NEW PACKAGE
- _________________________________________________________________
-
- The example file named ADDER1.ADA, illustrates how to use the
- previously studied package. There is nothing different about this
- program from any other program we have used except that it uses the
-
- Page 15-3
-
- Chapter 15 - Packages
-
- package we defined and named AdderPkg, which it ================
- acknowledges in lines 5 and 6 where it tells the ADDER1.ADA
- system to with the package and to use it in the ================
- program at hand. It also uses the renaming
- statement in line 19 which we will discuss
- later. The remainder of the program is simple, and you should have
- no trouble deciphering it. The primary purpose of these two
- examples is to illustrate how to write a library package.
-
- In line 17 we declare an array of type MY_ARRAY and at this time
- we supply the range limits for the subscript. You may begin to see
- the flexibility in this method of array declaration, but we will
- study it in detail later.
-
-
-
- THE with CLAUSE
- _________________________________________________________________
-
- It is finally time for a complete definition of just what the with
- clause does for us. When we with a package into our program, we
- are telling the system that we wish to have everything that is
- declared in the specification of that package available for our use
- in this program. Accordingly, the system will look at the items
- declared in the specification for that package and every time we
- use one of those items, it will see that we have the correct number
- of parameters and that we have the types declared for each
- parameter correctly. Note that this happens during compilation and
- explains why Ada is said to be compiled separately, but not
- independently of other compilation units. In a sense, the
- resources available in the withed package act as though they are
- extensions to the Ada programming language. Because of this, the
- with clause is called a context clause.
-
- When you arrive at the linking operation, the withed packages are
- automatically added into the executable file, as are any other
- packages that are withed by the package you have explicitly told
- the system to with into your program. Note that the package named
- STANDARD is automatically withed into every Ada program,
- subprogram, or package. The package named STANDARD defines many
- of the predefined entities such as INTEGER, BOOLEAN, FLOAT, etc.
-
- In a large program, it is possible to with the same package several
- times since it is used in several packages. You can be assured
- that only one copy of the package will be included during the
- linking operation. Multiple copies will not be stored.
-
- One other point must be made before leaving this topic, and that
- is the fact that all with clauses must be at the beginning of the
- program or package. There is a good reason for this. The
- dependent packages, and hence the overall program structure must
- be given at the beginning of each package making it easy to
- ascertain the overall structure without being forced to search
- through the entire listing for each package.
-
- Page 15-4
-
- Chapter 15 - Packages
-
-
- THE use CLAUSE
- _________________________________________________________________
-
- The use clause in Ada allows you to use a shorthand when naming
- procedures, functions, variables, etc, from a package. Instead of
- using the extended naming convention, or the so called "dot"
- notation, and including the package name followed by the procedure
- name, dotted together, you can simply use the procedure name and
- let the system figure out what package it is coming from. In most
- of the programs we have studied so far, we have included the
- Text_IO package in a use clause. If the use clause were omitted
- we would have to identify the package in each use of the procedures
- used. Put("This is Ada"); would have to be changed to read
- Text_IO.Put("This is Ada");, which clutters up the listing a bit
- but removes all ambiguity.
-
- Because it is possible to get a different procedure than the one
- you are expecting under very unusual conditions of overloaded
- procedure names, the use of the use clause is falling into some
- disrepute in the software engineering literature. Without the use
- clause, you are forced to type in additional information for each
- procedure call, but it leads to no ambiguity and therefore follows
- the basic premise of Ada that a program is written once but read
- many times. The extra keystrokes are worth the trouble to include
- them.
-
- Use of the use clause is a matter of personal taste or possibly a
- style dictated by a project style guide.
-
-
-
- RENAMING A PROCEDURE
- _________________________________________________________________
-
- A procedure can be renamed in order to reduce the length of the
- identifier, especially if a rather long extended name is required.
- It may be better to use a more descriptive name for the actual use
- of a generic or general purpose procedure. The method of renaming
- is illustrated in lines 19 and 20 of this program. Of most
- importance is the fact that the entire list of formal parameters
- must be repeated. This is done so that the definition of the new
- procedure name is complete and should be of help during program
- debugging.
-
- Use of the new name, which is of course only a synonym and not a
- new procedure, is illustrated in line 35 of this program.
-
- If you compiled the previous file, you can compile, link, and
- execute this one to see that the system knows how to link the two
- together.
-
-
-
-
- Page 15-5
-
- Chapter 15 - Packages
-
- COMBINING FILES
- _________________________________________________________________
-
- If you wish, you could combine the two files, provided you appended
- the second file to the end of the first. The compiler would then
- compile all three in succession, after which you could link the
- results, and execute the result. The library files must be
- compiled first so that the compiler can check the types in the
- procedure call to see that they agree, so putting them before the
- calling program conforms to this rule. If you did put them in a
- single file, you would still need the statements in lines 5 and 6
- to tell the system to with and use the library file defined earlier
- in the file, because the compiler would consider them to be three
- separate compilations.
-
-
-
- ANOTHER METHOD OF COMBINING FILES
- _________________________________________________________________
-
- The example program named ADDER2.ADA illustrates ================
- another way to combine the last two files, in ADDER2.ADA
- this case including the package in the ================
- declaration part of the program. The
- specification part of the package is in lines
- 15 through 19, and the body is in lines 27 through 38. In this
- case, a new type is defined between the two parts to illustrate
- that it can be done. Since the package is compiled as a part of
- the main program, it does not have to be mentioned in a with
- statement. The compiler knows that it is a part of the program,
- but the use must be mentioned to tell the system where to get the
- procedure name and the type. Of course the use can be omitted and
- the extended naming convention used for all references to the
- package.
-
- Even though the body is defined after the variable New_Array is
- declared in line 23, this variable is not directly available for
- use in the body, because the package structure effectively builds
- a strong wall around the enclosed statements, and nothing can get
- in or out. The only inputs to and outputs from the body are those
- defined in the specification part of the package. Of course the
- variable New_Array is available to the procedure because it is
- passed in as a parameter, but is not directly visible.
-
- One other difference occurs here that is different from the last
- two files. This embedded package is not available for use by any
- other program, because it is enclosed within this program, and is
- not therefore a library package. The entire file contains only one
- compilation unit.
-
-
-
-
-
-
- Page 15-6
-
- Chapter 15 - Packages
-
- ORDER OF DECLARATIONS
- _________________________________________________________________
-
- This is a fine point, but a very important point if you get a
- compile error that you do not understand. If you were allowed to
- include a variable declaration after you declare a procedure, it
- is possible for the tiny variable declaration to get lost, or at
- least hard to find in the listing. The designers of Ada decided
- to force you to put the little things first and the bigger things
- last by making a rule that says, "No variable, constant, type, or
- subtype can be declared in any declaration block following the
- declaration of a procedure, function or package body." It may be
- an unnecessary rule, but it does exist and is checked by all
- validated Ada compilers.
- You should compile and execute this program and you will see that
- it truly is identical to the previous two files combined.
-
-
- ANOTHER KIND OF SEPARATE COMPILATION
- _________________________________________________________________
-
- The example file named ADDER3.ADA illustrates ================
- still another method of separate compilation. ADDER3.ADA
- This program is identical to the last except ================
- that the package body is removed to a separate
- file for separate compilation, and is called a
- stub. The statement in line 27 indicates to the compiler that the
- body will be found elsewhere. Although this illustrates separate
- compilation of a package body, the same method can be used for
- separate compilation of a procedure. This could be used if you
- wished to remove a large procedure from the logic defined here to
- make it more manageable.
-
- The separately compiled body is found in the ================
- file named ADDERSTB.ADA, which begins with the ADDERSTB.ADA
- reserved word separate which indicates that this ================
- is a stub. The main program, or whatever other
- package, procedure, or function, that uses this
- stub is defined in parentheses following the reserved word separate
- to tell the compiler where this is used. This stub cannot be
- called or used by any other program, because it is in truth part
- of the program Adder3, not a general purpose program. Any
- variables, types, procedures, etc, that are available for use at
- the point where the stub is used, are available at the point where
- the stub is defined. The stub therefore has the same environment
- as the environment existing at the point of use, in this case line
- 27 of ADDER3.ADA.
-
-
- ORDER OF COMPILATION FOR THE STUB
- _________________________________________________________________
-
- Since all of the variables, types, etc must be made available to
- the stub, the using program must be compiled before the stub itself
-
- Page 15-7
-
- Chapter 15 - Packages
-
- is compiled. After both are compiled, the program can be linked
- and executed. You should compile ADDER3.ADA first, then
- ADDERSTB.ADA should be compiled, and finally ADDER3 should be
- linked. You will then have an executable ADDER3 program.
-
-
-
- ORDER OF COMPILATION IS NOT MYSTERIOUS
- _________________________________________________________________
-
- The example files included with this chapter are intended to
- illustrate to you the required order of compilation in a meaningful
- way, not as a group of rules to be memorized. If you understand
- the dependencies of files on one another, the order of compilation
- will make sense, and you will be able to intelligently arrange your
- programs to use the Ada type checking between the various
- separately compiled files. Remember that Ada, unlike Pascal, was
- designed to allow the development of huge programs that require
- separate compilation facilities, and yet retain the strong type
- checking between modules.
-
-
-
- A PACKAGE WITH AN INITIALIZATION PART
- _________________________________________________________________
-
- The example file named ADDER4.ADA illustrates ================
- one more feature of a package. This program is ADDER4.ADA
- nearly identical to the first program in this ================
- chapter. Both files which comprise the first
- example program have been incorporated into a
- single file for ease of compilation, and the variable named Total
- has been made global within the package. Since it is global within
- the package, it can be referred to by any subprogram in the package
- or in the initialization section as illustrated in lines 23 and 24.
- This section is optional but can be included in any package.
-
- Note that the initialization section is only executed once, at load
- time. For that reason, this program will not operate exactly as
- the first one did. The result that is output is identical in both
- cases, but the additional calls will not produce the same result
- because the variable Total is not cleared to zero during each call
- in this example program as it is in the first example. The
- initialization section only initializes the variable once, and it
- is impossible to call this section of code from within the
- executable part of the package.
-
-
-
-
-
-
-
-
-
- Page 15-8
-
- Chapter 15 - Packages
-
- PROGRAMMING EXERCISES
- _________________________________________________________________
-
- 1. Remove the package body from ADDER2.ADA and make it a stub.
- Compile the two resulting files in the correct order and link
- and execute the resulting program.
-
- 2. Remove all use clauses from the program named FORMATS.ADA in
- the last chapter, and prefix the I/O procedure calls with the
- proper package names. It should be clear to you that there
- can be no naming conflicts after this is done.
-
- 3. Change the name of the two compilation units in ADDERPKG.ADA
- without modifying the filename, and modify ADDER1.ADA to
- correspond to the new package name. Use a name that contains
- more characters than your operating system permits for a
- filename. Compile each file and link them together to result
- in an executable program.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Page 15-9