1
 package Bird_Package is 

    type Bird_Type is tagged private;

    procedure  Init(A_Bird : out Bird_Type; Name : in String);

    function   Name(A_Bird : in Bird_Type) return String;

    function   Call(A_Bird : in Bird_Type) return String;

    function   Type_Name(A_Bird : in Bird_Type) return String;

    procedure  Put(A_Bird : in Bird_Type);

 private

    type Bird_Type is tagged record
    My_Name : String (1..6);
     end record;
 end Bird_Package;

Package Body Bird_Package is


procedure Init(A_Bird: out Bird_Type; Name : in String) is
begin
     A_Bird.My_Name := Name;
 end Init;


 function Name(A_Bird : in Bird_Type) return String is 
 begin
    return A_Bird.A_Name;
 end Name;


 function Call(A_Bird : in Bird_Type) return String is
   begin
    return "Squawwwwwwk!";
 end Call;


function Type_Name(A_Bird : in Bird_Type) return String is
 begin
    return "Bird";
 end Type_Name;

procedure Put(A_Bird : in Bird_Type'Class) is
begin
        Put( Name(A_Bird) );
    Put( ' ' );
    Put( Type_Name(A_Bird) );
    Put( " says " );
    Put( Call(A_Bird) );
  end Put;
  end Bird_Package;

I have a problem with the package body I do not understand what Bird_Type'Class is so therefore I do not know how to apply it in my client program. It keeps telling me that the expected type is Bird_Type'Class, but the type it is finding is Standard String. Help is appreciated, thank you

j.Shry
  • 29
  • 5
  • Is there a procedure or function I can add to fix the body so it will work? – j.Shry Oct 20 '16 at 01:29
  • You seem to want to use the Put procedure from Ada.Text_IO, but you have no context clause stating a dependency upon Ada.Text_IO. Within your Put procedure you call Put while passing it a string, but the only Put procedure in your package is the Put procedure you define taking a parameter of Bird_Type'Class. By the way, the Put in the package body takes a parameter of Bird_Type'Class, while the Put in the package specification takes a type of Bird_Type. They are not the same thing. A Bird_Type'Class is any type rooted at Bird_Type, or inherited from Bird_Type. – Jim Rogers Oct 20 '16 at 02:12
  • This is the way it was given to me, I have to keep that Bird_Type is in the specification while Bird_Type'Class is in the body. I need to work in procedures and functions to get the body to compile, I however, cannot figure out how to do so – j.Shry Oct 20 '16 at 02:31
  • If anyone could give me a way to do this or a way to just get the program to compile I would greatly appreciate it – j.Shry Oct 20 '16 at 02:38
  • Insert the following line before the first line of the package body: with Ada.Text_IO; use Ada.Text_IO; This will declare a dependency upon the package Ada.Text_IO, and will also make the contents of that package visible to your package body. – Jim Rogers Oct 20 '16 at 03:43
  • Okay, that took away all but one error now I have: type of "A_Bird" does not match – j.Shry Oct 20 '16 at 03:49
  • Use Bird_Type in both the package specification for the Put procedure and the package body for the Put procedure. Bird_Type is different from Bird_Type'Class. The types must agree in both parts of the package. Note also that there is an error in the function Name. It tries to return A_Bird.A_Name. A_Name is not a field in Bird_Type. The field name is My_Name. – Jim Rogers Oct 20 '16 at 04:19
  • Interesting, someone's been deleting comments again - and not just mine. –  Oct 20 '16 at 13:00

2 Answers2

2

It seems that you have been set a classwork problem to fix up some low-quality code (or maybe it’s tricky on purpose ...). And if no one has taught you about ’Class before setting a problem involving it it’s not surprising that you should flounder.

Bird_Type is tagged, so presumably the intention is that there should be child types derived from Bird_Type (Parrot, Goose, ...), and that they should override the subprograms appropriately (a Parrot might still call "Squawwwwwk!" but a Goose would "Honk"; so Goose would override Call, but Parrot would inherit from Bird_Type).

Now, you want a Put that will invoke the right Call, and that is exactly what procedure Put(A_Bird : in Bird_Type’Class) does; the A_Bird parameter is either a Bird_Type or some type derived from it (e.g. Goose), and the call to Call will dispatch to the appropriate subprogram.

But the spec you’ve been given doesn’t use a classwide parameter, so if you just write

procedure Put(A_Bird : in Bird_Type) is
begin
   Put( Name(A_Bird) );
   Put( ' ' );
   Put( Type_Name(A_Bird) );
   Put( " says " );
   Put( Call(A_Bird) );
end Put;

then when it comes to the last line the only type it can see is Bird_Type and so it will just "Squawwwwk!" regardless.

But the spec says that you have to provide a Put with this parameter profile.

There is nothing wrong with having two versions of Put in the body, one taking a parameter of type Bird_Type and the other of type Bird_Type’Class. You could try implementing the spec’s Put like

procedure Put (A_Bird : in Bird_Type) is
begin
   Put (Bird_Type'Class (A_Bird));
end Put;

(after the existing Put with the classwide parameter); but unfortunately this leads to ambiguity,

$ gnatmake bird_package.adb
gcc -c bird_package.adb
bird_package.adb:43:07: ambiguous expression (cannot resolve "Put")
bird_package.adb:43:07: possible interpretation at bird_package.ads:13
bird_package.adb:43:07: possible interpretation at line 30
gnatmake: "bird_package.adb" compilation error

which can be fixed by

procedure Put (A_Bird : in Bird_Type) is
   procedure Classwide_Put (A_Bird : in Bird_Type'Class)
     renames Put;
begin
   Classwide_Put (Bird_Type'Class (A_Bird));
end Put;

But, that all said, the Right Way for this problem is to alter the spec Put to take a classwide parameter!

Simon Wright
  • 25,108
  • 2
  • 35
  • 62
0
with Ada.Text_Io; use Ada.Text_IO;
Package Body Bird_Package is


   procedure Init(A_Bird: out Bird_Type; Name : in String) is
   begin
      A_Bird.My_Name := Name;
   end Init;


   function Name(A_Bird : in Bird_Type) return String is 
   begin
      return A_Bird.My_Name;
   end Name;


   function Call(A_Bird : in Bird_Type) return String is
   begin
      return "Squawwwwwwk!";
   end Call;


   function Type_Name(A_Bird : in Bird_Type) return String is
   begin
      return "Bird";
   end Type_Name;

   procedure Put(A_Bird : in Bird_Type) is
   begin
      Put( Name(A_Bird) );
      Put( ' ' );
      Put( Type_Name(A_Bird) );
      Put( " says " );
      Put( Call(A_Bird) );
   end Put;
 end Bird_Package;
Jim Rogers
  • 4,822
  • 1
  • 11
  • 24
  • There is still a run-time problem in the package. The field Bird_Type.My_Name is defined as being String(1..6), which means it holds exactly 6 characters. Procedure Init contains a second parameter of type String, which can be a string of any size. A run time error will occur when you try to assign a name to a bird which is not exactly 6 characters long. You should consider how you will avoid this problem. – Jim Rogers Oct 20 '16 at 04:31