Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The type of a Loop Parameter

Tags:

ada

A beginner's question, I'm afraid. I need to record the position (index) of a particular element in an array. Consider the following:

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is

    Ten : constant Positive := 10;

    type ArrayIndex is new Positive range 1 .. Ten;

    type MyRecord is record
        firstItem  : Integer;
        secondItem : Integer;
    end record;

    TheRecords : array (1 .. Ten) of MyRecord;

    indexOfElement50  :  ArrayIndex := 1;

begin

    -- set the values in TheRecords

    for i in TheRecords'Range loop
        TheRecords(i).firstItem  := i * 10;
        TheRecords(i).secondItem := i * 20;
    end loop;

    -- find which element of TheRecords has a
    -- firstItem with a value of 50

    for i in TheRecords'Range loop
        if TheRecords(i).firstItem = 50 then
            -- this next line is horrible: I should
            -- not be required to do type casting
            -- in a strongly-typed language.

            indexOfElement50 := ArrayIndex(i);
            exit;
        end if;
    end loop;

    Put(ArrayIndex'image(indexOfElement50));

end Main;

Everything down to the comment "find which element of TheRecords has a firstItem with a value of 50" is just setting up the problem I have (in a much larger program, of course).

Although coming from a C and Python world, I have been trying to be religious about strong typing in Ada. So, I have defined "indexOfElement50" carefully, and I would like it to be the index to the element in TheRecords which has a firstItem of 50. The loop starting under the comment is the code which searches for that element. And finds it!

But then I have to cast i to be an ArrayIndex. And casting is so wrong in a strongly typed world. I have tried using indexOfElement50 as the loop parameter, but the compiler won't have any of that.

So, it seems that I am forced either to declare indexOfElement50 as an integer (which breaks the guideline of restricting ranges as much as possible), or to perform type casting (which is great in C, but which I shouldn't be doing in a strongly-typed language).

Or, which is more likely, I have missed something really obvious and this will be pointed out enthusiastically by the experts.

like image 661
Chris Hobbs Avatar asked Dec 22 '22 17:12

Chris Hobbs


1 Answers

I’d be inclined to reverse the approach a little.

with Ada.Text_IO; use Ada.Text_IO;

procedure Main is

You really don’t need to have a constant named Ten with value 10! What if you wanted to make it 12 later?

   type MyRecord is record
      firstItem  : Integer;
      secondItem : Integer;
   end record;

We want an array of records, but let’s postpone the decision of how long it needs to be ...

   type Record_Array is array (Positive range <>) of MyRecord;

... and define a test array, whose size happens to be 10 but could be anything.

   TheRecords : Record_Array (1 .. 10);

A valid result (for this test program) can only be in TheRecords’Range, but let’s add an out-of-range value to indicate ’not found’.

   subtype Possible_Index is Natural range 0 .. TheRecords'Last;
   indexOfElement50  : Possible_Index := 0;  -- indicates 'not found'

OK!

begin

   -- set the values in TheRecords

   for i in TheRecords'Range loop
      TheRecords(i).firstItem  := i * 10;
      TheRecords(i).secondItem := i * 20;
   end loop;

   -- find which element of TheRecords has a
   -- firstItem with a value of 50

   for i in TheRecords'Range loop
      if TheRecords(i).firstItem = 50 then
         indexOfElement50 := i;
         exit;
      end if;
   end loop;

   Put_Line (indexOfElement50'Image); -- legal in Ada2012

end Main;
like image 108
Simon Wright Avatar answered Feb 05 '23 06:02

Simon Wright