Packages
Introduction
Package Provide Services
- A package is a syntactic unit that provides services to a client
- More generic term: a Module
- Syntactic unit: language syntax provides a means of defining the beginning, end, and name of the unit.
- Services: procedures, functions, types, constants, exceptions
- Example: Ada.Text_IO
- Examples in other languages: Java classes and packages, C, C++: header .h files, proposals; Python, Objective C: Modules
- Motivation:
- Break a program into separate parts
- Provide a means of defining reusable tool libraries (eg Ada.Strings.Unbounded)
- Provide a means of defining defining abstract data types (eg Containers)
- Requirements - what the package system should provide:
- Separate compilation, with type checking between modules ;w
- Access control
Package are Modules
- Programming languages need to provide modules
- Encapsulate routines, types, etc
- Provide access control (for ADTs)
- Ada modules are called packages
- A package is a library of types and procedures (and functions)
- Example: Ada.Text_IO
- Can also contain constants, exceptions, other packages etc.
- Sounds like a class:
- Both contain methods/procedures
- BUT ...
Packages, Classes, and Types
- Classes are types
- Packages contain types
- Typically contain record types that contain fields
Packages Have Two Parts
- A package has two parts:
- Specification: Public type names and procedure signatures
- Body: Private procedure implementations (ie bodies)
- Package normally has TWO FILES:
- foo.ads - ada specification for package foo
- foo.adb - ada body for package foo
-- File foo.ads
package foo is -- Specification for package foo
procedure this(i: Integer);
procedure that(i: Integer);
...
end foo;
-- File whatever.adb
package body foo is -- Body (ie implementation) of package foo
procedure this(i: Integer) is
...
end this;
procedure that(i: Integer) is
...
end that;
...
end foo;
Question: ...
Question: where are the type implementations
Type implementations are typically in the (private section of the) specification
- Many types have private implementation
- Some types have public implementation
Example Package
Packages and ADTs
- Packages are frequent used to implement Abstract Data Types (ADT)
- Abstract: Focus on certain details, ignore other details
- ADT:
- Focus on: What it does (eg ADT provides user with type names and procedure signatures)
- Ignore: How it does it (ie user cannot see how ADT implements the what)
- ADT implementation requires access control:
- Public: What it does (eg type names and procedure signatures)
- Private: How it does it
Definition: Client of a Package
- Definition: Client of a class: method or class that uses
the class and its methods
-
Example code for client of class Person:
Person p = new
Person();
- Definition: Client of package P: Routine or package that
uses the types and routines defined in package P
- Our programs have been clients of several packages:
- Example code for client of package ada.text_io:
put("Hello");
- Example code for client of package
ada.integer_text_io:
get(i);
- Example of regular use of term: Client of a tutor is someone who uses the tutors services.
Files and Compilations
Packages and Files
- Normally a package is stored in 2 files:
- mypkg.ads - contains specifictation
- mypkg.adb - contains body
- This is actually gnat specific
- Suggested by Richard Stallman (of gnu fame)
Packages: Normal Compilation
- Compiling client will automatically compile required packages
-
gnatmake pairclient
compiles client and package
- Assume
pairclient.adb
, pairpkg.ads
,
pairpkg.adb
are all
in the same directory
-
gnatmake pairclient
creates following files:
pairpkg.ali
pairpkg.o
pairclient.ali
pairclient.o
pairclient.exe
- The
.ali
files contain library information about the compile
- The
.o
files contain machine code for the given
routine or package, but no code from (other) packages
-
pairclient.o
contains call to distanceToOrigin,
but it does not contain the code for distanceToOrigin
- Where is machine code for distanceToOrigin?
- The link step of gnatmake joins the
.o
files
and any library routines, and then
creates the executable pairclient.exe
- Other compilations possibilities are discussed later
- Example: compiling only the body and spec
Gnatmake is Smart
- Gnatmake is smart: it only recompiles if needed
- If
pairpkg.o
and/or pairclient.o
already exist,
gnatmake pairclient will only recompile them if needed
- If a .adb file is newer than its .o file, gnatmake recompiles the .adb file
Basic Syntax and Semantics
Package Specification and Body
- A package definition has two parts:
- Specification - provides the public view of the package:
- Typically contains:
- Names of Types
- Declarations of procedures and functions
- Constants
- Implementation of types is normally private
- Body:
- Contains implementation of procedures declared in spec
Spec and Body Consistency
- Every routine declared in the spec
must be defined in the body
- The signatures in the spec and body must be identical
- Parameter names, types, and order must be identical
- Function return types must be identical
- How does this contrast with Java?
Visibility of Package to Client
- Visibility to the client:
- Visible: function
distanceToOrigin
, etc
- Visible: Name of type
Pair
- Hidden: Implementation (ie fields) of type
Pair
- Hidden: Implementation of function
distanceToOrigin
,
etc
- Example:
with pairpkg; use pairpkg;
procedure clientX is
p: Pair;
begin
p.x := 3; -- Syntax error:
The error message is somewhat cryptic:
-
invalid prefix in selected component "p"
- A "selected component" is a name that uses dot notation
to denote a component of a record or a part of a package
(or some other things that we don't cover)
- Thus, the error message means that "p" is an invalid
prefix in the selected component "p.x"
Package Visibility Between Spec and Body
- Visibility to Body
- Visible: Name of type
Pair
- Visible: Implementation (ie fields) of type
Pair
- Entire spec is visible to body
- Visibility to Spec
- The body is not visible to spec
- Neither is the client, of course
Package Visibility
- Visibility of Specification
- Public section: visible everywhere (including private section)
- Typically available for client: Exceptions, Type Names, Constants, Routines
- Private section: visible only to body
- Visibility of Body: visible to nothing
- Note: This does not take child packages into account
With and Use and Packages
With and Use
- With and Use in Specification affect spec and body, but not client
- With and Use in Body affects body only
More on Use
- At top of file, use statement affects entire file
- The effect of a use statement can be localized
- In a declaration section, a use statement affects only the enclosing scope
with vs import vs include
- Modules in other languages (which are semantic): Java classes and packages, C, C++: header .h files, proposals; Python, Objective C: Modules
- One issue is transitivity:
- With statements do not have the transitive property:
- If A withs B and B withs C, then the routines in C are not available in A
- Not suprisingly, the same is true for use
- Example of transitive property: if x = y and y = z then x = z
- What about Java import statements?
- What about C and C++ #include?
- If file A contains an #include statement (example: #include or #include "stdio.h") does a textual inclusion
of stdio.h into the file. If stdio.h itself contains a header, that is also textually
included in A!
- Problems with includes:
- Multiple includes: If A includes both B and C and both B and C include D, then A will have two copies of D
- Lots of extra processing (and reprocessing) of headers, especially with templates
- Nothing similar happens with with
Files and Compilations - Continued
More on Compiling Packages
- When compiling pairclient, gnatmake sees that it needs
.o
files
for pairpkg and integer_text_io and so it:
- Compiles
pairpkg.adb
, creating pairpkg.o
- Finds
integer_text_io.o
in a library
Compiling Package Specs and Bodies Independently
- Specs and bodies can be checked independently
- Checking the spec -
gnatmake pairpkg.ads
:
- Checks for syntax errors in
pairpkg.ads
- Generates
pairpkg.ali
- Gives an error message because
pairpkg.ads
generates no code
- Can avoid error message with
gnatmake -gnatc pairpkg.ads
- Doesn't look at body
- Checking the body -
gnatmake pairpkg.adb
:
- Checks for syntax errors in
pairpkg.adb
- Checks for that
pairpkg.adb
is consistent
with pairpkg.ads
- Generates
pairpkg.ali
- Generates
pairpkg.o
- No executable generated
- Syntax error if spec not available
Compiling Client and Package Specs Without Body
- Can check client for consistency with spec
- Even if body does not exist (yet)
gnatmake pairclient
:
- Assume pairpkg.adb does not exist (yet)
- Checks for syntax errors in
pairclient.adb
- Checks for that
pairclient.adb
is consistent
with pairpkg.ads
- Generates
pairclient.ali
- Generates
pairclient.o
- No executable generated
- Syntax error since body not found
Compilation and Linking
- Consider pairclient.adb, pairpkg.ads, pairpkg.adb
- gnatmake pairpkg creates files pairpkg.ali and pairpkg.o
- .o files contain machine language versions
- .ali files contain information about compilation and package dependencies
- gnatmake pairclient creates files pairclient.ali and pairclient.o
- It will also compile pairpkg if pairpkg is not already compiled
- Compilation checks consistency between spec and client and between spec and body
- Thus, teams can work independently on the client and body, using the spec as a contract
- Note that when using library routines (eg Ada.Text_IO.Put), the
compiler must be able to find the .ads and .ali files for this routine
- Holes - The package body and client both call routines that are not in the file
- The client calls the package, and both call IO routines
- The addresses of these calls are left blank in the .o files (since they are not known
at compile time)
- These holes are fixed at link time
- The final step of the compilation process is linking, which does two main things:
- Linking joins pairclient.o and pairpkg.o and any library routines (eg io routines)
into a single executable (pairclient.exe on a windows machine)
- Linking fills in the holes with the addresses of the external routines
- The linker can calculate these addresses since it knows where each .o goes in the
.exe
- This description simplifies the process some; in particular, there may be some library
routines that are accessed dynamically (eg .dll files)
Classes, Packages, Records
Types and Modules: Conflated in Java
- A Java class is both a Type and a Module
- Java conflates the concepts of type and module.
- A class is a type but a module contains a type
- In Ada, a package is a module that (typically) contains a record type.
- Both classes and records are used to define composite types with fields