Type/Subprogram Interpretation Question

Hello,

I would like to define a subprogram which has the same name but different type signatures.

In this case, I have the “Generic_Operation” subprogram, which has a “Input : U8_Array” parameter version and a “Input : String” parameter version.

The desired code form is presented here:

  with Ada.Text_IO; use Ada.Text_IO;                                                                                                                                                     
                                                                                                                                                                                                  
  procedure Desired_Form is                                                                                                                                                                          
    type U8 is mod 2**8;                                                                                                                                                                                  
    type U8_Array is array (Natural range <>) of U8;                                                                                                                                                      
    Operation_A : constant U8 := 1;                                                                                                                                                                       
    Operation_B : constant U8 := 2;                                                                                                                                                                       
    Operation_C : constant U8 := 3;                                                                                                                                                                       
                                                                                                                                                                                                          
    function Generic_Operation                                                                                                                                                                            
     (Operation : U8;                                                                                                                                                                                  
      Input     : U8_Array)                                                                                                                                                                            
      return U8_Array                                                                                                                                                                                  
    is                                                                                                                                                                                               
    begin                                                                                                                                                                                                 
     return ( 16#FF#, Operation ) & Input;                                                                                                                                                               
    end Generic_Operation;                                                                                                                                                                           
                                                                                                                                                                                                          
    function Generic_Operation                                                                                                                                                                            
    (Operation : U8;                                                                                                                                                                              
     Input     : String)                                                                                                                                                                       
     return U8_Array                                                                                                                                                                                   
    is                                                                                                                                                                                               
    begin                                                                                                                                                                                            
      return ( 16#01#,  Operation );                                                                                                                                                                      
    end Generic_Operation;                                                                                                                                                                           
                                                                                                                                                                                                          
  begin                                                                                                                                                                                                   
                                                                                                                                                                                                          
    declare                                                                                                                                                                                          
     Binary_Blob : U8_Array :=                                                                                                                                                                           
     Generic_Operation (Operation_A, (16#00#, 16#C0#)) &                                                                                                                                          
     Generic_Operation (Operation_B, "Test");                                                                                                                                                     
    begin                                                                                                                                                                                                 
     null;                                                                                                                                                                                          
    end;                                                                                                                                                                                                  
                                                                                                                                                                                                          
  end Desired_Form;                                                                                                                                                                                          
                       

On compilation, I get the following errors:
desired_form.adb:35:07: ambiguous expression (cannot resolve “Generic_Operation”)
desired_form.adb:35:07: possible interpretation at line 22
desired_form.adb:35:07: possible interpretation at line 13

This implies that the line:

Generic_Operation (Operation_A, (16#00#, 16#C0#)) &     

could be used as an input to the U8_Array or the String version of “Generic_Operation”.

With this consideration, I comment out the U8_Array version and recompile this code:

  with Ada.Text_IO; use Ada.Text_IO;                                                                                                                                                     
                                                                                                                                                                                                  
  procedure String_Form_Only is                                                                                                                                                                          
    type U8 is mod 2**8;                                                                                                                                                                                  
    type U8_Array is array (Natural range <>) of U8;                                                                                                                                                      
    Operation_A : constant U8 := 1;                                                                                                                                                                       
    Operation_B : constant U8 := 2;                                                                                                                                                                       
    Operation_C : constant U8 := 3;                                                                                                                                                                       
                                                                                                                                                                                                          
    -- function Generic_Operation                                                                                                                                                                            
    --  (Operation : U8;                                                                                                                                                                                  
    --   Input     : U8_Array)                                                                                                                                                                            
    --   return U8_Array                                                                                                                                                                                  
    --  is                                                                                                                                                                                               
    --  begin                                                                                                                                                                                                 
    --   return ( 16#FF#, Operation ) & Input;                                                                                                                                                               
    --  end Generic_Operation;                                                                                                                                                                           
                                                                                                                                                                                                          
    function Generic_Operation                                                                                                                                                                            
    (Operation : U8;                                                                                                                                                                              
     Input     : String)                                                                                                                                                                       
     return U8_Array                                                                                                                                                                                   
    is                                                                                                                                                                                               
    begin                                                                                                                                                                                            
      return ( 16#01#,  Operation );                                                                                                                                                                      
    end Generic_Operation;                                                                                                                                                                           
                                                                                                                                                                                                          
  begin                                                                                                                                                                                                   
                                                                                                                                                                                                          
    declare                                                                                                                                                                                          
     Binary_Blob : U8_Array :=                                                                                                                                                                           
     Generic_Operation (Operation_A, (16#00#, 16#C0#)) &                                                                                                                                          
     Generic_Operation (Operation_B, "Test");                                                                                                                                                     
    begin                                                                                                                                                                                                 
     null;                                                                                                                                                                                          
    end;                                                                                                                                                                                                  
                                                                                                                                                                                                          
  end String_Form_Only;

Since either interpretation (line 22, or line 13) is possible (at least according to the errors), just having the one interpretation on line 22 should be satisfactory, but on compilation I get the errors:

  desired_formtype_test.adb:35:40: expected type "Standard.Character"                                                                    
  string_form_only.adb:35:40: found type universal integer                                                                                                                                                       
  string_form_only.adb:35:48: expected type "Standard.Character"                                                                                                                                                 
  string_form_only.adb:35:48: found type universal integer                                                                                                                                                       

What I find interesting and somewhat surprising is that the compiler considers the types U8_Array and String different enough to not allow implicit conversion (in the string_form_only.adb example), but not different enough (in the desired.adb example) to match the invocation with the correct subprogram signature.

I can get the compiler to compile the code with no errors if I explicitly identify the array as a U8_Array, as in:

  Generic_Operation (Operation_A, U8_Array'(16#00#, 16#C0#) &

I don’t understand why this is necessary in order for the compiler to match the correct subprogram signature for the Desired_Form program code.

I am using gnatmake which is calling gcc version:
x86_64-linux-gnu-gcc-10 (Ubuntu 10.5.0-1ubuntu1~22.04) 10.5.0

Could somebody help explain the nature of these observations?

Thanks,
N

ObjectAda V10.5U3 also rejects the array aggregate as ambiguous, citing ARM 8.6(31). GNAT 12.3 and 13.2 give the same error you report. So it seems that qualification is required by the language.

(:picky: this is actually an overloaded operation, not a generic one)

The String_Form_Only code fails because the first call to Generic_Operation tries to pass an array of hex values, not a string.

Interesting that the compiler here (GCC 13.2) is happy to accept the unquailfied array if there’s no overloaded string version to confuse it!

I wonder if it is just the double ambiguity that is causing trouble. It doesn’t know what type the literals need to be until it knows the array type, but it doesn’t know the array type because of the overloaded function calls.

If you make two separate U8 variables and assign the literals to them, then put those into your array aggregate instead, does the ambiguity go away as well?

This fails, too:

Binary_Blob : U8_Array :=
  Generic_Operation (Operation_A, (U8'(16#00#), U8'(16#C0#))) &
  Generic_Operation (Operation_B, "Test");