Encapsulation in Ada is determined by where—in which section of a package—a declaration appears (see figure 1). In languages such as C++ and Java, a tagged type that is fully declared in the visible part of a package specification corresponds to a class whose fields are considered public. Alternatively, a tagged type may be declared as a private type in the visible part of a package specification, with its full declaration in the private part. In this case, the type name is accessible outside the package, but the fields correspond to what would be called protected in C++ and Java. The type’s inheritable operations may likewise appear in either the visible or the private part of the package specification, corresponding to public and protected methods/functions, respectively. An operation declared in a package body is not inherited; it corresponds to a private function/method in C++ and Java.
Declarations in the visible part are visible within any program component that can access the package. Declarations in the private part are only visible within the implementation of the containing package and within the implementation (including private parts) of child units. With their privileged visibility into the private sections of parent units, child units are often used to model subclasses, declaring tagged types that inherit from the parent tagged type, since the implementation of subclass operations generally needs to access superclass state data. A subclass that does not need to access its superclass’s representation can be defined with looser coupling, declaring the new tagged type in a “client” package that gains access to the superclass’s package through a “with” clause.
Figure 1: An entity declared in the visible part of a package specification is visible (may be referenced) from any unit that can reference the package. In contrast, an entity declared in the private part of a package specification is visible only within the implementation of that package and within the implementation of child units. An entity declared within a package body is completely encapsulated: it is visible within that package body but not to client or child units.
Below, see an example of a tagged type in Ada. This example, and the others in this section, are derived from the UML class diagram shown in figure 2.
package Node_Pkg is
type Node is tagged private;
procedure Set_Id (Item : in Node; Id : in Integer);
function Id (Item : in Node) return Integer;
procedure Write (Item : in Node);
procedure Read (Item : out Node);
type Node is tagged record
Id : Integer;
An object of type Node
has an Id
field. The primitive operations for Node
are the procedures Set_Id
, and Read
, and the function Id
. Since Node
is a private type, the Id
field of a Node
object cannot be directly referenced from a client (“with-ing”) unit; instead, such a unit needs to invoke the Id
function or Get_Id
procedure. The Id
field can be directly referenced from the body of Node_Pkg
and also from the implementation of child units.
Figure 2: This class diagram shows a class Node, an interface Encryptable, and a class DataNode that inherits from Node and implements Encryptable. DataNode implicitly inherits the Id field and the Set_Id and Id operations from Node, overrides Put and Get from Node, and implements Encrypt and Decrypt from Encryptable.
Abstract Types and Interfaces
A tagged type in Ada may be declared as abstract, which prevents object creation and allows the declaration of abstract, or bodyless primitive operations. An interface type, or simply an interface, is a restricted form of abstract tagged type with no implementation-oriented properties. Thus an interface type has no data components, and in general each primitive operation will be declared as abstract. Ada also allows an interface procedure to be declared as null, in which case it is implicitly given an implementation (body) that immediately returns. This is useful when a natural default behavior for a procedure is to do nothing.
Here is an example of an interface type in Ada:
package Encryptable_Pkg is
type Encryptable is interface;
procedure Encrypt (Item : in out Encryptable) is abstract;
procedure Decrypt (Item : in out Encryptable) is abstract;