Num of variants in an Enum

Suppose I have an enumeration type,

type E = (A, B);

How can ask the compiler to refer to its length? E'Length is allowed only for arrays :sob:, E'Size is bit size :straight_ruler:, and E'Last gives B.

Currently I’m using E'Pos (E'Last), but I wanted to be sure there wasn’t a better way.

Well, what exactly do you mean by length?
From the additional information it seems like you mean the cardinality.
If that’s the case then it should, in full generality, be:

Temp   : Constant Integer := E'Pos( E'Last ) - E'Pos( E'First );
Length : Constant Natural := (If Temp < 0 then 0 else Natural'Succ(Temp) );

But, since E'Pos( E'First ) is 0, this should devolve to being exactly E'Pos( E'Last ) + 1. (Because by definition, the first enumeration-value’s position is zero, the next one, and so on.) And so the need for the +1 fix-up.

So, why the overly-complex answer?

Generics, and subtypes.
In certain situations, admittedly uncommon, these details matter and can yield surprising results. (Especially if you’re getting into the less “well-traveled” parts of the language; I once found an error in GNAT with generics where whether or not a character type was provided for a discrete-type altered the functionality.)

2 Likes

Correct; my apology for the poor vocabulary. I meant to write “number of items”.

…and I neglected to add 1 to my formula.

But… why would / how could Temp < 0?

Edit: To be clear, I see that you wrote, “in full generality”, but I’m not sure what you mean by that… Are you referring to types other than enumerations?

(Sorry if the question is dumb; I may just be a bit too tired right now…)

Subranges/slices.

Type Index is range -128..127;
Type Unconstrained is array(Index range <>) of Whatever;

Procedure Show_Bounds( Data : Unconstrained ) is
Begin
   Ada.Text_IO.Put_Line( Index'Image(Data'First) & " .." & Index'Image(Data'Last) );
End Show_Bounds;

EXAMLPE:
Declare
   Thing : Constant Unconstrained:= ( 1..-11 => <> );
Begin
   Show_Bounds( Thing );
End EXAMPLE;

This must print 1 ..-11, as per the RM, even though the array itself has zero length. So there are cases where your upperbound is less than the lowerbound, signifying the null range.

I’d have to re-examine it, but IIRC you can force this sort of situation with a generic:

Generic
   Type Discrete is (<>);
Package Example is
   Subtype Positive_Discrete is Discrete range
      Discrete'Succ( Discrete'First )..Discrete'Last;
End Example;
--…
Type Singleton is (Just_Me);
Package Actual_Example is new Example( Singleton );

Consider Actual_Example.Positive_Discrete, and its range’s endpoints.

What language is this?

In Ada

generic -- Num_Values
   type Discrete is (<>);
function Num_Values (Low : in Discrete; High : in Discrete) return Natural;
-- Returns the number of values in Low .. High

function Num_Values (Low : in Discrete; High : in Discrete) return Natural is
   (if Low > High then 0 else Discrete'Pos (High) - Discrete'Pos (Low) + 1);

Modula-2, apparently! or Pascal. :grin: I meant

type E is (A, B);

My apologies for the syntax error; I was at a different machine & didn’t think to glance at the other one, nor to write up a new example beforehand, so something in my head fell back on Modula-2 and Pascal, and possibly Rust (since I used “Enum” in the thread title).

@JC001 @OneWingedShark
Thank you for the detailed answers.