Packages
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);
- Now let's learn to design and build our own packages
Packages + Records = Classes
- Records and Packages combined are similar (but not
identical) to classes:
- Packages contain procedures, classes contain
methods (ie encapsulatation)
- Packages contain Types, classes are types
- Fields in record types correspond to
fields in Java classes
- Packages can contain multiple types; classes are a
single type
- Although, a class can contain nested classes
- Packages and classes both allow access control
- Let's build a package that is similar to Java class Pair
Java Class Pair
- A type for Pairs
- Two fields: x and y
- One method: (city block) distance from (x, y) to (0, 0)
- Code:
class Pair
{
int x, y;
int distanceToOrigin() // How far to origin on streets
{
return Math.abs(x) + Math.abs(y);
}
}
// Client for class Pair
class PairClient
{
Pair p;
p = new Pair();
p.x = 1;
p.y = 2;
Sop(p.distanceToOrigin());
}
Later we will consider access control (ie make fields x and y
private)
Ada Type Pair in Package PairPkg
- Let's make package PairPkg that provides the functionality of class Pair
- Package PairPkg must contain definitions for two things:
- A record type
Pair
- Function
distanceToOrigin
PairPkg: Requires TWO Files
- Package PairPkg requires 2 files:
-
pairpkg.ads
: Package Specification - contains the public interface
-
pairpkg.adb
: Package Body - contains the implementation
- pairpkg.ads - the package specification:
-- Defines types and interfaces for subroutines
package PairPkg is
type Pair is record
x, y: Integer;
end record
-- Street distance
function distanceToOrigin(p: Pair) return Integer;
end PairPkg;
pairpkg.adb - the package body:
-- Defines subroutine implementations
package body PairPkg is
function distanceToOrigin(p: Pair) return Integer is
begin
return abs p.x + abs p.y;
end distanceToOrigin;
end PairPkg;
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?
PairPkg Client
- Client of Package PairPkg
with ada.integer_text_io; use ada.integer_text_io;
with pairpkg; use pairpkg;
procedure pairclient is
p: Pair;
begin
p.x := 1;
p.y := 2;
put(distanceToOrigin(p));
end pairclient;
Notice the with and use of package pairpkg
- Type
Pair
and function
distanceToOrigin
are defined in package Pairpkg and
visible in client
- Pair fields (ie implementation) are visible in client
This is a third file: pairclient.adb
PairPkg Client - Without the Use Statement
- Without the use statement, the package name must be given
-- Client of package pairpkg: file pairclient.adb
with ada.integer_text_io; use ada.integer_text_io;
with pairpkg;
procedure pairclient is
p: pairpkg.Pair;
begin
p.x := 1;
p.y := 2;
put(pairpkg.distanceToOrigin(p));
end pairclient;
Packages: Normal Compilation
- Compiling client will automatically compile client
-
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
creates the executable pairclient.exe
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
- 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
- Other compilations possibilities are discussed later
- Example: compiling only the body and spec
Java Access Control: Make Fields x and y Private
- Now, let's make fields x and y private
- Code:
class Pair {
private int x, y;
Pair(int x, int y){
this.x = x; this.y = y;
}
int distanceToOrigin() // How far to origin {
return x + y;
}
}
// Client
class PairClient{
Pair p;
p = new Pair(1, 2);
Sop(p.distanceToOrigin());
// p.x = 3; // Syntax error
}
Visibility to the client:
- Visible: Method
distanceToOrigin
- Visible: Name of type
Pair
- Hidden: Implementation (ie fields) of type
Pair
Ada Access Control: Make Type Pair Private
- We will hide the implementation of type
Pair
- Constructor-like function now required
- Code:
------------------------------------------------------
-- Package Specification: file pairpkg.ads
package PairPkg is
-- Public section of package
type Pair is private; -- Only type name is public
function newPair(x, y: Integer) return Pair;
function distanceToOrigin(p: Pair) return Integer;
-- Private section of package
private -- Code below is NOT visible to client
type Pair is record -- Type implementation is private
x, y: Integer;
end record
end PairPkg;
------------------------------------------------------
------------------------------------------------------
-- Package Body: file pairpkg.adb
package body PairPkg is
function newPair(x, y: Integer) return Pair is
temp: Pair := (x, y);
begin
return temp;
end newPair;
function distanceToOrigin(p: Pair) return Integer is
begin
return p.x + p.y;
end distanceToOrigin;
end PairPkg;
------------------------------------------------------
------------------------------------------------------
-- Client of package pairpkg: file pairclient.adb
with ada.integer_text_io; use ada.integer_text_io;
with pairpkg; use pairpkg;
procedure pairclient is
p: Pair;
begin
p := newPair(1, 2);
put(distanceToOrigin(p));
-- p.x := 3; -- Syntax error
end pairclient;
Visibility of Package to Client
- Visibility to the client:
- Visible: function
distanceToOrigin
- Visible: Name of type
Pair
- Hidden: Implementation (ie fields) of type
Pair
- 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
Now Add More Methods/Subroutines
Implicit (Java) vs Explicit (Ada) Parameters
- The difference between packages and classes highlights the
existence of Java's (and other typical oo languages') implicit parameters
- Consider the difference between these two pairs of statements:
// Java
Sop(p3.distanceToOrigin());
Sop(p3.distanceBetween(p4));
-- Ada
put(distanceToOrigin(p3));
put(distanceBetween(p3, p4));
In the java code, p3 is an implicit parameter. In the Ada code,
p3 is an explicit parameter
Consider a diagram showing p3, p4 and the parameters, in both languages
- Notice how we typically don't distinguish the variable's type
and the object's class
Another example: Compare these two Pair
clients:
// Java
Pair p5 = new Pair(1, 2);
Pair p6 = new Pair(3, 4);
S.o.p(p5.toString());
S.o.p(q6.toString());
-- Ada
declare
Pair p5 = newPair(1, 2);
Pair p6 = newPair(3, 4);
begin
put(toString(p5));
put(toString(p6));
In both clients, the Pair is passed to as a parameter to toString
In Ada, the explicit formal parameter is p
- First, p takes the value of p5, and then p takes the value of p6
- The explicit formal parameter must be used to access fields (ie access with p.x)
In Java, the implicit formal parameter is this
- First, this takes the value of p5, and then this takes the value of
p6
The implicit formal parameter is optional in accessing fields (ie access with x
or this.x)
Conflating Modules and Types
- Java conflates the mechanisms of type and module
- To conflate is to join together
- Ada separates the concepts of a module and a type
- For our purposes, a module is a syntactic unit that combines program units
such as types, constants, and subroutines
Comparison: Types, Classes and Packages
- A Java class defines a type
- A type is a set of ... and a set of ...
- To define the type, the class defines 2 things:
- The set of values for the type:
- Specified by the fields of the class/object
- The fields specify the structure of an instance of the class
- The operations for the type
- The methods that operate on an instance of the class
- Specified (obviously) by methods in the class
- Class also provides access control for hiding implementation
- Compare classes with packages:
- Package contains a type definition (typically a record type)
- Package contains definitions of procedures and functions
- That operate on that type.
- The package's private section also provides access control
Comparision of Classes and Packages: Classes
- What is a class?
- A Type for declaring reference variables
- A template for creation of instances of the class (ie
allocating instance variables)
- A repository of methods that operate on instances of the class
(with implicit parameter
this
)
- Methods with void return type (ie procedures)
- Methods with non-void return type(ie functions)
- A repository (ie a library)
that can be used without instances of the class, containing
- Constants (eg Math.PI)
- Methods with non void return type (eg Math.sqrt(...)
- Methods with void return type (eg System.gc(), System.exit()
- Other classes (eg class java.awt.geom.Ellipse2D.Double is
a nested public static class defined in the abstract class
java.awt.geom.Ellipse2D)
Comparision of Classes and Packages: Packages
- Packages provide similar services:
- They contain types (rather than are types
- They contain procedures and functions that operate on
instances of the types
- Explict parameters are required
- They are libraries of
- procedures and functions
- constants
- exceptions
Summary: Ada Package Specification
- Has two sections: public and private
- Public section is everything above keyword
private
- Private section is everything following keyword
private
- Public section can define following services:
- Names of (private) Types
- Can also provide type implementation, but normally we follow good software
engineering practice and keep the implementation private
- Procedure and function signatures
- Constants
- Exceptions
- Private section typically contains
- Implementation of private types
- Private constants and types
- Example: Constant MaxWordSize in WordPkg
- Example: Constant size and type BigNum in BigNumPkg
Summary: Ada Package Body
- Must contain an implementation of every procedure and routine defined in
specification
- Signatures in package and body must match exactly (eg name, mode, type of parameters)
- Private section of package specification is visible in package body
- Package body is not visible to outside
- Package body can contain routines, types, constants, etc that are not defined in
the specification. These routines are private to the body.
Summary: Ada Package Client
- The client must have a use clause for any package it refers to
- The client can only see the public section of the spec
Summary of Visibility of Packages
- Specification contains public and private sections
- Client and body can access items declared in the public
section of the specification
- Body can also access items declared in the private section of
the specification
- Entire body is completely private.
- Entities declared in the public section can have a
private implementation,
which is given in the private section
- Why does the spec contain the implementation?
Packages: Summary Overview
- Similar to classes: A class is a type, a package contains a type
- Packages contain code that provides some or all of the following
services for clients:
- New Types
- Procedures and functions that operate on those types
- Constants, either of new or existing types (eg Null: Word, or Pi: Float)
- Procedure and function libraries (Not necessarily using new types)
- Exceptions
- Implementation uses two files
- mypkg.ads: Specification for Package MyPkg
- mypkg.adb: Body (ie implementation) for Package MyPkg
- Specification is similar, in some ways, to a java interface
Some Sample Packages
- Some example packages:
- Package PairPkg
- Package Word (ie words are contiguous non-white-space)
- Package Bignum
- Package IntStackPkg
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