Search code examples
ada

Possible to declare generic function for both constrained and unconstrained arrays?


Say I have a formal array type and a function to find the index of a given element in that array like so:

generic
   type T is private;
   type T_index is (<>);
   type T_array is array(T_index range <>) of T;
function FindIndexGeneric(array: T_array; element: T; elementFound: out Boolean) return T_index;

Instantiating this for an unconstrained array such as string works fine:

function FindIndexString is new FindIndexGeneric
  (T=>Character, T_index=>Positive, T_array=>String);

But the same doesn't work when I have a constrained array:

type userIDIndex is Integer range 1..6;
type userID is array(userIDIndex) of Character;
function FindIndexUserID is new FindIndexGeneric
  (T=>Character, T_index=>userIDIndex, T_array=>userID);
-- error: expect unconstrained array in instantiation of "T_array"

I can make constrained arrays work by changing the formal array declaration line to:

type T_array is array(T_index) of T;

but then I cant instantiate unconstrained arrays with this.

Given the core logic in my array functions (FindIndexGeneric) are the same, I don't want to create multiple versions of it, one each for constrained and unconstrained arrays.

Is there a way to make a generic function operate on both constrained and unconstrained arrays?


Solution

  • I don't think there is a way to instantiate a generic with both constrained and unconstrained arrays, but there is a kind of work-around: you can instantiate with an unconstrained array, and define a constrained subtype of the unconstrained array type, and then you can call the instantiated generic function with a parameter of the constrained subtype. Like this:

    generic
       type T is private;
       type T_index is (<>);
       type T_array is array (T_index range <>) of T;
    ...
    type userIDIndex is Integer range 1..6;
    type userIDUnconstrained is
       array (userIDIndex range <>) of Character;
    subtype userID is userIDUnconstrained (userIDIndex);
    
    function FindIndexUserID is new FindIndexGeneric
      (T       => Character,
       T_index => userIDIndex,
       T_array => userIDUnconstrained);
    

    Then you can call FindIndexUserID with a parameter of the constrained (sub)type userID. However, note that in the body of the generic you should traverse the array parameter by iterating over its index range (arry'Range), not over the whole T_index.