Say I have package P1 with an enumerated type Enum defined there.
package P1 is
type Enum is (a, b);
end;
Then a package P2 which subtypes P1.Enum:
with P1;
package P2 is
subtype Enum is P1.Enum;
end;
Then a procedure P3 which in its turn subtypes P2.Enum:
with P2;
procedure P3 is
subtype Enum is P2.Enum;
x : Enum;
begin
x := a;
end;
Out of architectural constraints, P3 can reference P2, P2 can reference P1, but P3 is not allowed to know of P1.
The issue is that a is not visible to P3.
GNAT complains rightfully:
p3.adb:6:08: "a" is not visible
p3.adb:6:08: non-visible declaration at p1.ads:2
… and so does HAC:
p3.adb: 6:9-9: undefined identifier: a
The question now: is there a more or less elegant way of making the enumeration items a, b available to P3 ?
You can use P3.Enum'First to get it, though this is simply because a is the first item. If this is all you need, then use it.
However, if you actually need various values, then you can use “private constants” —I’m drawing a blank on the actual LRM term— but you use this like:
with P1;
Package P2 is
subtype Enum is P1.Enum;
Interesting_Value : Constant Enum;
Meaningful_Value : Constant Enum;
Private
Interesting_Value : Constant Enum:= P1.A;
Meaningful_Value : Constant Enum:= P1.B;
End P2;
Thus you can retrieve the values, albeit renamed, from P2.
Now, as to the reason for this: Ada treats enum value-names as a parameterless function returning that particular value — so, just as you cannot use subprograms from P1 without withing it, you cannot use the named values without withing it.
Note: this does mean that you could rewrite the “private constants” as functions:
with P1;
Package P2 is
subtype Enum is P1.Enum;
Function Interesting_Value return Enum renames P1.A;
Function Meaningful_Value return Enum renames P1.B;
End P2;
You can rename literals in P2 if they are not literals:
A : E renames P1.A;
That does not work with character literals.
Though literals are functions in Ada, they are not primitive functions. Primitive operations require no visibility, they cannot be hidden. Compare this with numeric literals. They are kind of primitive functions being of a universal type (universal_real or universal_integer) and “inherited” per conversion to the specific type. This is why you need no acrobatic with them.