Jerunh
Jerunh

Reputation: 514

When comparing Ada Scalar type With a subtype do I need to range check?

When comparing Ada Scalar type with a constrained subtype do I need to range check?

I know that in an assignment to the constrained subtype from the base type I am at risk to a Range_Check exception at runtime if I don't ensure that the value is within range prior to assignment.

But is this also true when performing a comparison? I would think that since the only knowledge the user wants back is a Boolean result, that no implicit conversion to the base type or range checking would be needed.

Please Note: I am looking for an answer that references the Ada95 LRM.

Example

declare
  type Day_Type is (SUN, MON, TUE, WED, THU, FRI, SAT);
  subtype Workday_Type is MON .. FRI; 

  Payday : constant Workday_Type := FRI;

    ...

  function Is_Payday (Day : Day_Type) 
      return Boolean is
  begin  
      return (Day = Payday);
  end Is_Payday;

begin

    -- Will this raise a RANGE_CHECK error in Is_Payday()?
    if Is_Payday(Day => SAT) then 
       ...
    elsif Is_Payday(Day => FRI) then
       ...       
    end if;

end;

What I've Found So Far...

I have not found the full answer. But I did find several interesting bits of data.

Operations of Discrete Types / Chapter 3.5.5 para 12 it says:

(31) For a subtype of a discrete type, the result delivered by the attribute Val might not belong to the subtype; similarly, the actual parameter of the attribute Pos need not belong to the subtype. The following relations are satisfied (in the absence of an exception) by these attributes:

S'Val(S'Pos(X)) = X
S'Pos(S'Val(N)) = N

(20) In addition to explicit type_conversions, type conversions are performed implicitly in situations where the expected type and the actual type of a construct differ, as is permitted by the type resolution rules (see 8.6). For example, an integer literal is of the type universal_integer, and is implicitly converted when assigned to a target of some specific integer type. Similarly, an actual parameter of a specific tagged type is implicitly converted when the corresponding formal parameter is of a class-wide type.

Even when the expected and actual types are the same, implicit subtype conversions are performed to adjust the array bounds (if any) of an operand to match the desired target subtype, or to raise Constraint_Error if the (possibly adjusted) value does not satisfy the constraints of the target subtype.

This seems to suggest that implicit type conversions will always be performed down to the subtype (the language is difficult for me to read). But I don't see anywhere that states a comparison performed between an subtype and a base type required.

I am also confused by the statement:

implicit subtype conversions are performed to adjust the array bounds (if any) of an operand to match the desired target subtype

  1. Does Array Bounds reference array types? or Is it referencing the range of the constrained subtype?
  2. Is there a Target Subtype if there is no subtype?

Ada 95 Rationale...


I have probably just missed the answer in my search. But I'm looking for definitive proof one way or another.

Sorry for the long read.

Upvotes: 3

Views: 682

Answers (2)

B98
B98

Reputation: 1239

Just like Simon Wright has explained, operations are those of a type, whereas subtype forms subsets of values of a type, not a different type with different operations.

For illustration, consider "+" in this:

type N is range 0 .. 10;

X : constant N := N'Base'(-1) + N'(2);

A number of Ada rules apply, and while IANALL, I remember LLawyers emphasizing that the rules are made so that producing the mathematically (logically) correct result is possible without raising exceptions even when, seemingly, some operation involves values exceeding a range along the way. There's a hint in LRM 4.5. So, I'd expect relational_operator rules, "="'s in particular, to be supportive, too.

Upvotes: 1

Simon Wright
Simon Wright

Reputation: 25511

You may find the Annotated ARM version (AARM95 3.2) helpful (note, your references were to the unmaintained AdaHome web site; prefer http://www.adaic.org).

A subtype has a type and possibly constraints:

type T is ...;
subtype S1 is T;            -- effectively a renaming of T
subtype S2 is T range ...;  -- (added) constraints

and the operations of the subtype are those of its type, which is why you can write the comparison Day = Payday without conversions. We know that a Workday_Type is a Day_Type, so we can just do the comparison directly.

It is true that Workday_Type (Day) = Payday runs the risk of CE, but there is no need for you or the compiler to do that.

Upvotes: 7

Related Questions