Packages
Declaration Protection
The package is the basic modularization unit of the Ada language, as is the class for Java and the header and implementation pair for C++. An Ada package contains three parts that, for GNAT, are separated into two files: .ads files contain public and private Ada specifications, and .adb files contain the implementation, or Ada bodies.
Java doesn't provide any means to cleanly separate the specification of methods from their implementation: they all appear in the same file. You can use interfaces to emulate having separate specifications, but this requires the use of OOP techniques which is not always practical.
Ada and C++ do offer separation between specifications and implementations out of the box, independent of OOP.
package Package_Name is
-- public specifications
private
-- private specifications
end Package_Name;
package body Package_Name is
-- implementation
end Package_Name;
Private types are useful for preventing the users of a package's types from depending on the types' implementation details. The private
keyword splits the package spec into "public" and "private" parts. That is somewhat analogous to C++'s partitioning of the class construct into different sections with different visibility properties. In Java, the encapsulation has to be done field by field, but in Ada the entire definition of a type can be hidden. For example:
package Types is
type Type_1 is private;
type Type_2 is private;
type Type_3 is private;
procedure P (X : Type_1);
...
private
procedure Q (Y : Type_1);
type Type_1 is new Integer range 1 .. 1000;
type Type_2 is array (Integer range 1 .. 1000) of Integer;
type Type_3 is record
A, B : Integer;
end record;
end Types;
Subprograms declared above the private
separator (such as P
) will be visible to the package user, and the ones below (such as Q
) will not. The body of the package, the implementation, has access to both parts.
Hierarchical Packages
Ada packages can be organized into hierarchies. A child unit can be declared in the following way:
-- root-child.ads
package Root.Child is
-- package spec goes here
end Root.Child;
-- root-child.adb
package body Root.Child is
-- package body goes here
end Root.Child;
Here, Root.Child
is a child package of Root
. The public part of Root.Child
has access to the public part of Root
. The private part of Child
has access to the private part of Root
, which is one of the main advantages of child packages. However, there is no visibility relationship between the two bodies. One common way to use this capability is to define subsystems around a hierarchical naming scheme.
Using Entities from Packages
Entities declared in the visible part of a package specification can be made accessible using a with
clause that references the package, which is similar to the C++ #include
directive. Visibility is implicit in Java: you can always access all classes located in your CLASSPATH. After a with
clause, entities needs to be prefixed by the name of their package, like a C++ namespace or a Java package. This prefix can be omitted if a use
clause is employed, similar to a C++ using namespace
or a Java import
.
[Ada]
-- pck.ads
package Pck is
My_Glob : Integer;
end Pck;
-- main.adb
with Pck;
procedure Main is
begin
Pck.My_Glob := 0;
end Main;
[C++]
// pck.h
namespace pck {
extern int myGlob;
}
// pck.cpp
namespace pck {
int myGlob;
}
// main.cpp
#include "pck.h"
int main (int argc, char ** argv) {
pck::myGlob = 0;
}
[Java]
// Globals.java
package pck;
public class Globals {
public static int myGlob;
}
// Main.java
public class Main {
public static void main (String [] argv) {
pck.Globals.myGlob = 0;
}
}