Packages are a mechanism to organize Ada code. They allow us to:
Encapsulate related entities: We can group logically related declarations and definitions together in a package. This helps organize our code into logical units.
Share entities: Entities declared in a package specification can be shared and accessed by other program units.
Hide implementation: The package specification declares the entities that are visible outside the package. The package body contains the implementation which is hidden from outside. This enforces information hiding.
We organize code in packages in the following way:
- Create a package specification with
package
keyword:
package PACKAGE_NAME is
-- declarations visible to the outside world
end PACKAGE_NAME;
- Create a package body with
package body
keyword:
package body PACKAGE_NAME is
-- implementation
end PACKAGE_NAME;
The entities declared in the package specification are visible outside the package and can be used by other program units. The package body contains the implementation which is hidden.
Related declarations can be grouped into logical packages to organize your code.
Using packages
You can include one package in another package in Ada using the with
clause.
For example, if you have two packages:
PACKAGE1 specification and body
PACKAGE2 specification and body
And you want to use entities (types, constants, variables, subprograms) from PACKAGE1 in PACKAGE2, you can do:
In the PACKAGE2 specification:
package PACKAGE2 is
with PACKAGE1; -- Include PACKAGE1
...
end PACKAGE2;
Now you can use the entities declared in PACKAGE1 within PACKAGE2. For example:
package body PACKAGE2 is
Variable1 : PACKAGE1.Variable_Type; -- Use variable from PACKAGE1
...
end PACKAGE2;
The with
clause makes the entities of the specified package visible within the current package. This allows modularization and reusability of code.
The with
clause is specified in the specification of the package, not the body. The bodies of the packages do not need a with
clause.
Subprogram Signature
A subprogram signature includes:
The subprogram name
The parameter names and modes (in, in out, out)
The parameter types
The return type (for functions)
It specifies the interface of the subprogram without defining the implementation.
The subprogram signature can be present in the package specification to expose the subprogram to other program units that use the package. The actual subprogram body is defined in the package body.
For example:
package PACKAGE_NAME is
-- Subprogram signature
procedure PROC_NAME (Param1 : in INTEGER;
Param2 : in out FLOAT);
-- More declarations...
end PACKAGE_NAME;
package body PACKAGE_NAME is
-- Subprogram body
procedure PROC_NAME (Param1 : in INTEGER;
Param2 : in out FLOAT) is
begin
-- Implementation
end PROC_NAME;
-- More body...
end PACKAGE_NAME;
Here the subprogram signature is defined in the package specification, making it visible outside the package. The actual subprogram body is defined in the package body.
This allows abstraction and information hiding, exposing only the interface of the subprogram to the outside world, hiding the implementation details.
Public members
Public members must be declared in the package specification in order to be visible and accessible to other program units that use the package.
Only the declarations in the package specification are visible outside of the package. The package body is not visible to other program units.
So for a member to be public and accessible, it must be declared in the package specification. This includes:
Types
Constants
Variables
Subprograms (signatures)
For example:
package PACKAGE_NAME is
-- Public type
type Public_Type is ...;
-- Public constant
Public_Constant : constant Integer := 10;
-- Public variable
Public_Variable : Integer;
-- Public subprogram signature
procedure Public_Procedure;
end PACKAGE_NAME;
package body PACKAGE_NAME is
-- Subprogram body
procedure Public_Procedure is
begin
...
end Public_Procedure;
end PACKAGE_NAME;
Here Public_Type
, Public_Constant
, Public_Variable
and the subprogram Public_Procedure
are all declared in the package specification, so they are public members and visible to other program units.
The package body only contains the implementation of Public_Procedure
, but not its declaration.
So in summary, for a member to be public it must be declared in the package specification, not just defined in the package body.
Note. When a member is not declared in the specification is private member. If you need to make a private member public the only way is to duplicate the signature in the package specification. This is something specific to Ada.
Private:
The "private" keyword in Ada is used to declare private members within a package specification. It has the following main purposes:
Information hiding: It hides the private members from other program units that use the package, exposing only the public interface. This achieves information hiding and encapsulation.
Compiler checking: The Ada compiler can check that private members are only accessed within the package itself and not from outside the package. This helps catch errors.
Flexibility: If a private member later needs to become public, we can simply move its declaration from the private section to the public section of the specification. This provides flexibility.
Complete specification: The package specification contains all necessary declarations, including private members, to fully specify the interface of the package.
The "private" keyword is used as follows in a package specification:
package PACKAGE_NAME is
-- Public declarations
private
-- Private declarations
end PACKAGE_NAME;
Anything declared after the "private" keyword is a private member that can only be accessed within the package body.
The benefits of private members are:
Information hiding
Compiler checking
Flexibility of implementation
Complete package specification
So in summary, the "private" keyword in Ada package specifications:
Declares private members that are hidden from other program units
Allows the compiler to check for proper encapsulation
Provides flexibility while maintaining a stable interface
Makes the package specification complete
Hope this explanation of the "private" keyword in Ada was helpful! Let me know if you have any other questions.
Public
The "private" and "public" keywords cannot alternate several times within an Ada package specification. They can only be used once, at the top level.
After the initial "public" section, if present, there must be exactly one "private" section. And after the "private" section, no further "public" or "private" sections are allowed.
The structure of an Ada package specification is:
Optional "public" section
Followed by required "private" section
No further "public" or "private" sections
So the keywords can only be used once, at the top level, to separate the initial public interface from the private implementation details:
package PACKAGE_NAME is
public
-- Public declarations
private
-- Private declarations
end PACKAGE_NAME;
Alternating "public" and "private" sections multiple times would not make sense and is not allowed by the language syntax.
The "public" section declares the elements of the interface that are visible to clients of the package.
The "private" section declares implementation details that are hidden from clients.
So alternating sections would break this concept of a clear separation between interface and implementation.
Standard Packages
There are many standard packages in the Ada language. These are packages that are part of the Ada language specification and are provided by all Ada compilers.
Some of the main standard packages in Ada are:
Ada.Text_IO: Provides routines for text input/output like read, write, put, get etc.
Ada.Integer_Text_IO: Provides text input/output for integer types.
Ada.Float_Text_IO: Provides text input/output for float types.
Ada.Calendar: Provides routines to work with dates and times.
Ada.Strings: Provides routines to manipulate strings.
Ada.Characters: Provides routines to manipulate characters.
Ada.Containers: Provides various container data structures like lists, maps, sets etc.
Ada.Exceptions: Provides routines to handle exceptions.
Ada.Numerics: Provides mathematical functions and number theoretic routines.
Ada.Sequential_IO: Provides routines for sequential file I/O.
Ada.Direct_IO: Provides routines for direct file I/O.
These and many other standard packages are defined in the Ada language specification and are included in all Ada compiler implementations.
They provide useful functionality like I/O, strings, containers, exceptions, numerical operations etc. so that programmers don't have to implement these from scratch.
The standard packages have a well-defined interface that is consistent across compilers, so code that uses the standard packages will be portable.
Programmers can use the standard packages in their Ada programs to perform common tasks, and know that their code will compile and run the same on any Ada compiler.
So the standard packages provide a useful library of routines that increase the usability and portability of the Ada language.
Package Manager
Currently, there is no comprehensive package manager for Ada similar to npm, pip, etc.
However, there are a few options for managing Ada library dependencies:
GNATproject files - GNAT, the GNU Ada compiler, uses GNATproject files to specify library dependencies. A GNATproject file lists the dependent Ada spec files and body files. When you compile a project with GNAT, it will automatically compile all dependent library projects specified in the GNATproject file.
ALI files - Ada Library (Object) files (.ali) are used to cache the results of compiling Ada specs. When a library changes, only the changed .ali files need to be recompiled. Ada projects can list .ali files as dependencies, and the compiler will only recompile changed .ali files.
Makefiles - You can manage Ada library dependencies using Makefiles. Makefiles list the dependent Ada source files and library .ali files, and make can rebuild projects when dependencies change.
Ada Controller - A commercial tool that can be used to manage complex Ada projects and library dependencies. It tracks which libraries a project depends on and can automatically recompile projects when dependencies change.
AdaDev - Another commercial tool that provides a package manager for Ada. It allows installing Ada libraries from a central repository and manages library dependencies.
So while there is no single, dominant package manager for Ada like npm for JavaScript, there are some options for managing Ada library dependencies to some extent. But in general, dependency management in Ada is not as sophisticated as in other languages with dedicated package managers.
Disclaim: This article was created using Rix (AI)