comp.lang.ada
 help / color / mirror / Atom feed
* Polymorphism question
@ 1997-02-20  0:00 Robert Oeckl
  1997-02-20  0:00 ` Samuel Mize
  1997-02-23  0:00 ` Kirk Beitz
  0 siblings, 2 replies; 5+ messages in thread
From: Robert Oeckl @ 1997-02-20  0:00 UTC (permalink / raw)



I have problems to figure out, how Polymorphism works in Ada. I want to
know if and how the following is possible in Ada:

Suppose I have an abstact type A. Now I have two (non-abstract)
descendants B and C of A. Furthermore there is a descendant D of C. For
A an abstract procedure P1 is defined and for B and C P1 is overloaded.
I do also want to be able to call P1 with type D without explicitly
defining P1 for D, so that the procedure as defined for type C is
executed with type D.
Now I have a procedure P2 defined for type C. For type D I want to
overload this procedure. But in the overloaded procedure I want make a
call to P2 as defined for C, if possible without loosing the information
that the object is actually of type D inside the called procedure.

I hope my description of the problem is clear enough. I would greatly
appreciate any code-examples.

Thanks in advance,

Robert


------------------------------------
Robert Oeckl, graduate student
University of Wisconsin
Department of Physics
1150 University Avenue
Madison WI 53706-1390, USA

phone: +1 (608) 262-8947
e-mail: oeckl@pheno.physics.wisc.edu




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Polymorphism question
  1997-02-20  0:00 Polymorphism question Robert Oeckl
@ 1997-02-20  0:00 ` Samuel Mize
  1997-02-23  0:00 ` Kirk Beitz
  1 sibling, 0 replies; 5+ messages in thread
From: Samuel Mize @ 1997-02-20  0:00 UTC (permalink / raw)



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.







^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Polymorphism question
  1997-02-20  0:00 Polymorphism question Robert Oeckl
  1997-02-20  0:00 ` Samuel Mize
@ 1997-02-23  0:00 ` Kirk Beitz
  1997-02-23  0:00   ` Robert Dewar
  1997-02-23  0:00   ` Robert Dewar
  1 sibling, 2 replies; 5+ messages in thread
From: Kirk Beitz @ 1997-02-23  0:00 UTC (permalink / raw)



Robert Oeckl <oeckl@pheno.physics.wisc.edu> writes:

> 
> I have problems to figure out, how Polymorphism works in Ada. I want to
> know if and how the following is possible in Ada:
> 
> Suppose I have an abstact type A. Now I have two (non-abstract)
> descendants B and C of A. Furthermore there is a descendant D of C. For
> A an abstract procedure P1 is defined and for B and C P1 is overloaded.
>
> I do also want to be able to call P1 with type D without explicitly
> defining P1 for D, so that the procedure as defined for type C is
> executed with type D.

well, you are out of luck.  you must define P1 for type D separately.  that
is the nature of the abstract definition of P1.

> Now I have a procedure P2 defined for type C. For type D I want to
> overload this procedure. But in the overloaded procedure I want make a
> call to P2 as defined for C, if possible without loosing the information
> that the object is actually of type D inside the called procedure.

actually, those of us whom english is a first language use the word "losing"
to describe what you're talking about.  but other than that, i don't see
what it is you're trying to solve.






^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Polymorphism question
  1997-02-23  0:00 ` Kirk Beitz
  1997-02-23  0:00   ` Robert Dewar
@ 1997-02-23  0:00   ` Robert Dewar
  1 sibling, 0 replies; 5+ messages in thread
From: Robert Dewar @ 1997-02-23  0:00 UTC (permalink / raw)



Kirk answered Robert

<<> I have problems to figure out, how Polymorphism works in Ada. I want to
> know if and how the following is possible in Ada:
>
> Suppose I have an abstact type A. Now I have two (non-abstract)
> descendants B and C of A. Furthermore there is a descendant D of C. For
> A an abstract procedure P1 is defined and for B and C P1 is overloaded.
>
> I do also want to be able to call P1 with type D without explicitly
> defining P1 for D, so that the procedure as defined for type C is
> executed with type D.

well, you are out of luck.  you must define P1 for type D separately.  that
is the nature of the abstract definition of P1.
>>


Surely that is wrong. Once you have defined a non-abstract P1 for type C,
then it surely will be inherited by a non-abstract descendent D of C.
Surely we must assume in the above question that D is non-abstract.

package p is
   type a is abstract tagged null record;
   procedure p1 (arg : a) is abstract;

   type b is new a with null record;
   procedure p1 (arg : b);

   type c is new a with null record;
   procedure p1 (arg : c);

   type d is new c with null record;
end p;

type d has a non-abstract p1 available (the one declared for type c)





^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Polymorphism question
  1997-02-23  0:00 ` Kirk Beitz
@ 1997-02-23  0:00   ` Robert Dewar
  1997-02-23  0:00   ` Robert Dewar
  1 sibling, 0 replies; 5+ messages in thread
From: Robert Dewar @ 1997-02-23  0:00 UTC (permalink / raw)



Robert O asks

<<> Now I have a procedure P2 defined for type C. For type D I want to
> overload this procedure. But in the overloaded procedure I want make a
> call to P2 as defined for C, if possible without loosing the information
> that the object is actually of type D inside the called procedure.>>

To which Kirk gave the helpful :-) answer that loosing was misspelled.

But I suspect the help that Robert was looking for was how to make a call
to P2! This is easily done, just convert the argument to type C, so the
call looks like P2 (C (Arg)). This is a view conversion and indeed it
does not lose (or loose) the information that the object is actually of
type D. 

P.S. Kirk, it's a perfectly reasonable question. It might be easily assumed
that a conversion of the D object to type C would lose the tag (i.e. that
the result of the conversion would be a real C), but it is an important
part of the design that such conversions are NOT real conversions in this
sense, but simply provide a view of the D that looks like a C for the
purpose of the call, but a subsquent dispatching call will know that it
is really a D.

I hope I am correctly understanding both questions here!





^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~1997-02-23  0:00 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1997-02-20  0:00 Polymorphism question Robert Oeckl
1997-02-20  0:00 ` Samuel Mize
1997-02-23  0:00 ` Kirk Beitz
1997-02-23  0:00   ` Robert Dewar
1997-02-23  0:00   ` Robert Dewar

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