Ada's Serious Drawback: Package Names Cannot Be Used as Type Names
For developers adopting Ada, one of the most significant structural differences to overcome, especially when coming from other object-oriented languages, is how type hierarchies are organized.
Developers familiar with Java or C# are accustomed to a model where classes in the same package (namespace) can inherit from one another, forming a natural type hierarchy.
// A pseudo-code example in the style of Java/C#
// Types form an inheritance hierarchy within the 'widget' namespace.
package com.example.widget;
public class Widget { /*...*/ }
public class Window extends Widget { /*...*/ }
public class Button extends Widget { /*...*/ }
public class ToggleButton extends Button { /*...*/ }
public class CheckedButton extends Button { /*...*/ }
The structure where a base type Widget
and its derived type Window
coexist in the same namespace—also named Widget
—is extremely common and intuitive. However, Ada has a fundamental limitation when it comes to expressing such a type hierarchy by name.
Hierarchy Comparison: The Intuitive vs. The Explicit
Let’s assume we are building a GUI toolkit and compare the hierarchical structure in both languages. ToggleButton
and CheckedButton
inherit from Button
, while Button
and Window
inherit from Widget
.
The Java / C# Approach: An Inheritance-Based Type Hierarchy
Within a single package (namespace), classes form a direct type hierarchy through inheritance. The type’s name itself represents the concept.
Widget
/ \
Window Button
/ \
/ \
/ \
ToggleButton CheckedButton
The Ada Approach: A Package-Centric Hierarchy and the Inability to Use Package Names as Type Names
In Ada, everything must be separated into distinct packages (modules). To express the concept of Window
inheriting from Widget
, you must create a separate child package named Widget.Window
. Furthermore, because a package name cannot be used as a type name, you must declare a separate type to hold the object instance. In this case, we will name that type Object
.
Widget
|
Object
/ \
/ \
Window Button
| |
Object Object
/ \
/ \
ToggleButton CheckedButton
| |
Object Object
-- Example of variable declarations, showing the required '.Object' suffix.
-- Note: 'with' and 'use' clauses can be used to omit parts of the namespace.
my_widget : access Widget.Object;
my_window : access Widget.Window.Object;
my_button : access Widget.Button.Object;
my_toggle_button : access Widget.Button.ToggleButton.Object;
The necessity of writing Widget.Window.Object
where one might expect Widget.Window
results in a verbose structure that can appear cumbersome.
Conclusion: The Trade-Off for Reliability
This strict design philosophy in Ada can be a point of friction. The code becomes more verbose, and developers must forgo some of the more intuitive object-oriented patterns found in other languages.
However, this design is not arbitrary; it is a deliberate trade-off. This structural choice is often accepted because Ada provides unparalleled guarantees of safety and reliability. The language’s rigorous compile-time validation and powerful, built-in run-time checks continuously verify program correctness. For these guarantees, the verbosity and structural explicitness are considered a worthwhile price.