comp.lang.ada
 help / color / mirror / Atom feed
From: smize@news.imagin.net (Samuel Mize)
Subject: Re: Polymorphism question
Date: 1997/02/20
Date: 1997-02-20T00:00:00+00:00	[thread overview]
Message-ID: <5ejaqs$d7c@prime.imagin.net> (raw)
In-Reply-To: 330C9CB8.41C6@pheno.physics.wisc.edu


In article <330C9CB8.41C6@pheno.physics.wisc.edu>,
Robert Oeckl  <oeckl@pheno.physics.wisc.edu> wrote:
>I have problems to figure out, how Polymorphism works in Ada. I want to
>know if and how the following is possible in Ada:

Yes, it is.  Here's how polymorphism works in Ada.  First, you learn
the "polymorph self" spell -- wait, that's Dungeons & Dragons.

NOTE: by convention, "Ada" is Ada 95.  This capability is not in Ada 83.

NOTE ALSO: I don't have a compiler or ARM handy.  Consider the code
snippets to be suggestive, not authoritative.

In Ada, most data is unimorphic.  If you want a type to be polymorphic,
you must explicitly say so.  Such a type is a "tagged" type.  You
cannot derive a tagged type from a non-tagged type.  It must be a
record type (since you are planning to add fields to it).  The "tag"
is an implicit record field that identifies, for a specific object,
which exact type it is.

A "class" is a tree of related types: a specific tagged type and all
the tagged types derived from it.

Any type has "primitive" subprograms.[1]  A tagged type's primitive
subprograms may "dispatch" -- execute the appropriate procedure based
on the specific type of the controlling parameter or result.[2]

However, this only happens if the type of the controlling parameter
(or result) is not statically defined.  Thus, in the following,
P1, P2 and P3 can dispatch, but all the calls actually shown are
statically determined.  (I'll show dispatching next.)

  package T1_Class is
    type T1 is tagged record
        X: float;
      end record;
    procedure P1 (T: T1);
    procedure P2 (T: T1);
    procedure P3 (T: T1);
  end T1_Class;

  package T2_Class is
    type T2 is new T1 with record
        I: integer;  -- T2 has BOTH field X and field I
      end record;
    procedure P1 (T: T2);
    procedure P2 (T: T1);
  end T2_Class;

  procedure Example1 is
    X1: T1;
    X2: T2;
  begin
    P1 (X1); -- calls T1_Class.P1 -- A
    P3 (X1); -- calls T1_Class.P3 -- B

    P1 (X2); -- calls T2_Class.P1 -- C
    P3 (X2); -- calls T1_Class.P3 -- D
  end Example1;

You can view-convert a given tagged data item to any of its
"parent" types.  Thus, you can convert X2 up to type T1, but
you CANNOT convert X1 down to type T2 -- what would you use
for the value of field I?  The type conversion looks like:

    P1 ( T1(X2) ); -- calls T1_Class.P1

You can also tell Ada to dispatch, even though you have an
object of a specific type, by type-converting it to the
class of the object's type (or a parent type):

    P2 ( T1'class (X2) ); -- DISPATCHES to the P2 defined for
                          -- T1's actual type (based on its tag)

THE TAG TRAVELS WITH THE DATA ITEM and remains the same.  (It's
just another field of the record [3]).  Now, suppose that in
T1_Class.P1 we make the call:

    P2 ( T1'class (X2) ); -- E

When Example1 calls P1 at C, it will call T1_Class.P1; but when
T1_Class.P1 calls P2 at E, it will DISPATCH to call T2_Class.P2,
even though T2_Class did not exist when T1_Class's body was compiled!
The program doesn't lose the knowledge of what type the object
really is.

Finally, a data item can be of a class-wide type (WARNING: I don't
have an ARM handy.  I KNOW parameters can be class-wide, I THINK
variables can be.  I KNOW accesses-to-variables can be.)  A call
to a dispatching operation with a class-wide data item will, of
course, dispatch.

  procedure Example2 (P: T1'class) is
    type T_Class_Access is access T1'class;
    X1: aliased T1'class := P;
    X2: T_Class_Access := X1'Unchecked_Access;
  begin
    P1 (P); -- DISPATCHES based on tag of actual parameter
    P1 (X1); -- DISPATCHES
    P1 (X2.all); -- DISPATCHES
  end Example2;

I hope you find this a helpful introduction.  I understand there
is a paper discussing object-oriented programming in Ada somewhere
under http://www.adahome.com .  Certainly there you can get the
Ada 95 Rationale, which has a section on this very topic.

Samuel Mize

FOOTNOTES:
[1] Exactly which subprograms are "primitive" is based on the "freezing"
rules in Ada.  I don't know them off the top of my head.  The usual
idiom is to put each type and its subprograms in a distinct package;
these will all be primitive, and will be all the type's primitives.
This does not have to be a library-level package: in the following,
P1 is a primitive subprogram for T1, but P2 is not.

   package Enclosure is

     package T1_Class is
       type T1 is ...;
       procedure P1 (T: T1);
     end T1_Class;

     procedure P2 (T: T1);

  end Enclosure;

[2] A subprogram may have more than one controlling parameter/result, 
but you can't dispatch to two procedure bodies.  All the controlling
parameters, and the result (if controlling), must be of the same
specific type.  The rules are a little more complex than that, but
that's the basic idea.

[3] Not necessarily -- there are possible implementations of the Ada
functionality that don't use an actual record field as the tag.  If
you aren't building an Ada 95 compiler, don't worry about it.







  reply	other threads:[~1997-02-20  0:00 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1997-02-20  0:00 Polymorphism question Robert Oeckl
1997-02-20  0:00 ` Samuel Mize [this message]
1997-02-23  0:00 ` Kirk Beitz
1997-02-23  0:00   ` Robert Dewar
1997-02-23  0:00   ` Robert Dewar
replies disabled

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