5

I have a record and wanted some accessor function for it.

package Some_Package is                                                             

   type A is tagged record                                                          
      First_Field  : Integer;                                                       
      Second_Field : Character;                                                     
   end record;                                                                      

   type B is private;                                                               

   function Some_A (Some_B : B) return A;                                           

private                                                                             

   type B is tagged record                                                          
      Some_A : A;                                                                   
   end record;                                                                      

end Some_Package;

And here's what GNAT gives me:

some_package.ads:10:13: operation can be dispatching in only one type

This error is somewhat cryptic for Ada newbie and I'd appreciate some explanation what I did wrong and how to do it correctly.

1 Answers1

12

This is because of a specific rule in the ARM; there are two tagged types involved (B privately), and in Ada a subprogram can dispatch on one of its parameters or on the function result (actually, it would be OK if all the parameters and the result were the same tagged type). I think this is a consequence of Ada’s single-inheritance design.

Do you actually need A to be tagged? (I expect this is a cut-down version of the actual problem code).

If both A and B need to be tagged, the canonical solution for function Some_A is to make one of its parameters/results class-wide (a class-wide parameter isn’t dispatching):

function Some_A (Some_B : B'Class) return A;

or

function Some_A (Some_B : B) return A'Class;

depending on which makes more sense from the application point of view; guessing the second, you can then say

The_A : A’Class := Some_A (Some_B => The_B);

By the way, it would be clearer to readers, and wouldn’t lose much encapsulation, if you said

type B is tagged private;
Simon Wright
  • 25,108
  • 2
  • 35
  • 62
  • 1
    Great answer. There's only one thing I'd like to see clarified - what exactly 'to dispatch' means in this context? I tried some googling but it is used differently for different things in Ada context. –  Jul 25 '12 at 11:37
  • 2
    @Mikolaj: Check out the chapter on [Object Orientation](http://en.wikibooks.org/wiki/Ada_Programming/Object_Orientation) in the Ada Wikibook, [dispatching](http://en.wikibooks.org/wiki/Ada_Programming/Object_Orientation#Polymorphism.2C_class-wide_programming_and_dynamic_dispatching) in particular. – Marc C Jul 25 '12 at 13:47
  • @MarcC, I copied your link into the answer. Thanks. – Simon Wright Jul 25 '12 at 14:38
  • 1
    See also this about the [dispatch table](http://www2.adacore.com/gap-static/GNAT_Book/html/node19.htm) Dispatch table. I think (corrections welcome!) that your some_package code would have required 2 tables (Not one - Single inheritance) and therefore the code could not dynamically determine which table to use to dispatch on. – NWS Jul 26 '12 at 09:19