adaada2012

Idiomatic Way to Pass an Empty Enumeration to a Generic in Ada


I'm instantiating a generic package with an enumeration to access one of multiple values and use in subprogram overloading. I want to have a well-defined, compile-time checked set of values I can use and look up.

generic
    -- Different types because we don't want to ensure we never put
    -- beer in a wine class, or wine in a beer stein.  Our inventory
    -- never changes, for... reasons.
    type Wine is (<>);
    type Beer is (<>);
package Bar is
    type Wine_Glass is null record;
    type Beer_Stein is null record;

    -- Unopened cases/bottles of each.
    type Wine_Inventory is array (Wine) of Natural;
    type Beer_Inventory is array (Beer) of Natural;

    procedure Pour (G : in out Wine_Glass; W : in Wine);
    procedure Pour (S : in out Beer_Stein; B : in Beer);
end Bar;

What's the idiomatic to describe an empty enumeration?

with Bar;
procedure Wine_Tasting is
    type Sampling_Wine is (Tempranillo, Zinfandel, Merlot);
    pragma Unreferenced (Tempranillo, Zinfandel, Merlot);

    type No_Beer is (None);
    package Wine_Tasting_Bar is new Bar(Wine => Sampling_Wine, Beer => No_Beer);
    Stein : Wine_Tasting_Bar.Beer_Stein;
begin
    Wine_Tasting_Bar.Pour (Stein, None); -- legal!
end Wine_Tasting;

Is there a way to describe this such that Beer is an enumeration with no values, so that Pour can never been called with a Beer?


Solution

  • You have to declare an enumeration type with at least two values, and then declare a subtype with no values. You use the subtype to instantiate the generic:

    type Wine_Kind is (Red, White, Green);
    type Beer_Base is (Ale, Lager);
    subtype No_Beer is Beer_Base range Lager .. Ale;
    
    package Wine_Bar is new Bar (Wine => Wine_Kind, Beer => No_Beer);