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:

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.)

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…)

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.

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);

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).