Search code examples
recordada

Can’t use record’s discriminant within the record


My code is below. The compiler won’t let me use the discriminant var to control the size of the string name.

procedure p is

   type int is range 1 .. 10;
   type my (var : int) is record
      name : string (1 .. var); -- this var here is bad, why?
   end record;

   hh : my(6);

begin
   put (hh.name);
end p;

The error messages are

p.adb:4:23: expected type "Standard.Integer"
p.adb:4:23: found type "int" defined at line 2

Solution

  • It's due to Ada strong typing. Ada allows you to declare new integer and floating-point types which are not compatible with each other. The original intent was to prevent accidentally using values with one meaning as if they had a totally unrelated meaning, e.g.

    type Length is digits 15;  -- in meters
    type Mass is digits 15;    -- in kilograms
    L : Length;
    M : Mass;
    
    M := L;   -- error, caught at compile time
    

    The compiler catches this statement that doesn't make any sense because a "mass" variable can't hold a length. If everything were just Float or Long_Float the compiler wouldn't be able to catch it.

    What you've done is to create another integer type, int. As in the above example, values of your new type can't automatically be converted to Integer, which is the type of the index of String. (String is actually defined as array (Positive range <>) of Character with Pack;, but Positive is a subtype of Integer, and values can be automatically converted between Positive and Integer since they are really subtypes of the same base type.)

    Unfortunately, this isn't allowed either:

    type my(var : int) is record
       name : string (1 .. Integer(var)); -- this var here is bad why?
    end record;
    

    because of an Ada rule that the discriminant has to appear alone in this context. So your only option is to make int a subtype:

    subtype int is Integer range 0 .. 10;
    type my(var : int) is record
       name : string (1 .. var); -- this var here is bad why?
    end record;