1
votes
 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

2
Is there a procedure or function I can add to fix the body so it will work?j.Shry
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
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 soj.Shry
If anyone could give me a way to do this or a way to just get the program to compile I would greatly appreciate itj.Shry
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

2 Answers

2
votes

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!

0
votes
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;