comp.lang.ada
 help / color / mirror / Atom feed
From: Adam Beneschan <adam@irvine.com>
Subject: Re: Howto declare an Ada container with access to objects of a class hierachy
Date: Wed, 12 Jun 2013 18:46:55 -0700 (PDT)
Date: 2013-06-12T18:46:55-07:00	[thread overview]
Message-ID: <96caa993-0ba4-47da-b337-9aa1c7068029@googlegroups.com> (raw)
In-Reply-To: <78030778392775583.757462tc.schmidt-gmx.net@news1.open-news-network.org>

[Sorry if this is a double post.  Google is being obstinate.]

On Wednesday, June 12, 2013 5:43:22 PM UTC-7, Thomas Schmidt wrote:

> Hi,
> 
> Hoping this Is the right newsgroup for asking my question. 

Yes, it is.  Welcome.
 
> I want to set up a hashed set of accesses (allocated from heap) to objects 
> of a given class hierarchie (the top class may f.e. be called "Top"). I 
> decided to use "Ada.Containers.Indefinite_Hashed_Sets". The hash method 
> should be a primitive which may be overwritten by derived classes. I've 
> declared Tops hash functions formal parameter as of type "access Top". How 
> do I've to declare the sets Element_Type? I think if I use "Top'Access" it 
> wouldn't fit the hash functions 
> parameter type nor could I store objects of classes derived from "Top". 

First of all: I'm assuming that when you want a set of "accesses to
objects", you really mean that you want to work with your own accesses
(Ada's term for pointer), and you're going to allocate them yourself
with a "new" operator.  

If the access will be pointing to any object in the hierarchy, then
you'd declare an access type like this:

   type Top_Access is access all Top'Class;

The 'Class is needed because a Top_Access can point to any object in
the hierarchy.  (In some other object-oriented languages, you
automatically get a pointer to all classes in the hierarchy and you
can't declare something that says "This is a pointer to just this one
type and *only* this one type.  Ada is different.)

Now that you have an access type, you can use it as the Element_Type.
However, an *access* type is always a definite type, so you can use
Ada.Containers.Hashed_Sets instead of
Ada.Containers.Indefinite_Hashed_Sets.  

To instantiate the generic, you'll need a Hash function and an
Equivalent_Elements function.  You've declared a Hash function for Top
and all of the derived classes.  But you need a Hash function that
takes a Top_Access as a parameter (since Element_Type will be
Top_Access).  This is pretty easy to write, though:

   function Hash (A : not null Top_Access) return Ada.Containers.Hash_Type is
   begin
      return A.all.Hash;
   end Hash;

A.all is the object pointed to by A.  Its type is a *classwide* type
Top'Class -- that is, it is either Top or one of its derived classes.
A.all.Hash then calls the Hash function; and since A.all's type is a
classwide type, the result is that it will call the correct Hash for
whatever the object's type is.  Which is what you want.

You don't really need .all in this example; you can usually leave it
out if there's something else following.

   function Hash (A : not null Top_Access) return Ada.Containers.Hash_Type is
   begin
      return A.Hash;
   end Hash;

You'll also need something to use for Equivalent_Elements.  I'm
assuming that you've written a function Equiv for Top and its derived
types that looks like

   function Equiv (Left, Right : Top) return boolean;

   overriding
   function Equiv (Left, Right : Derived_Type_1) return boolean;

and so on.  So you could try to write

   function Equiv (Left, Right : not null Top_Access) return boolean is
   begin
      return Left.Equiv (Right.all);
   end Equiv;

(You do need .all after Right here.)  The problem is that this will
cause a problem if Left and Right are pointing to objects of different
types, this will raise an exception.  So you'll need to check:

   with Ada.Tags;  --- you'll need this up at the top
   
   function Equiv (Left, Right : not null Top_Access) return boolean is
   begin
      --if Ada.Tags."=" (Left.all'Tag, Right.all'Tag)  -- or just
      if Ada.Tags."=" (Left'Tag, Right'Tag) then
          return Left.Equiv (Right.all);
      else 
          return false;
      end if;
   end Equiv;

The check is kind of ugly, but I don't know of another way to test
whether two class-wide objects are the same type.

Now you can instantiate:

   package Top_Set is new Ada.Containers.Hashed_Sets
      (Element_Type        => Top_Access,
       Hash                => Hash,
       Equivalent_Elements => Equiv);

(If you really didn't want to use accesses, you could instantiate
Ada.Containers.Indefinite_Hashed_Sets with Element_Type => Top'Class.
You'd have to write your own Hash and Equiv functions that take a
Top'Class as parameters, and they'd look similar to the ones I showed
you above that take Top_Access as parameters.  A *classwide* type is an indefinite type, so you'd need Indefinite_Hashed_Sets here.)

I realize this is a bit complicated.  Hope this helps,

                             -- Adam

  reply	other threads:[~2013-06-13  1:46 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-06-13  0:43 Howto declare an Ada container with access to objects of a class hierachy Thomas Schmidt
2013-06-13  1:46 ` Adam Beneschan [this message]
2013-06-13 12:12   ` Thomas Schmidt
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox