comp.lang.ada
 help / color / mirror / Atom feed
* Re: How to?: Re-dispatching within an inherited method
  1999-08-09  0:00 How to?: Re-dispatching within an inherited method Anthony E. Glover
@ 1999-08-09  0:00 ` David C. Hoos, Sr.
  1999-08-17  0:00   ` Matthew Heaney
  0 siblings, 1 reply; 8+ messages in thread
From: David C. Hoos, Sr. @ 1999-08-09  0:00 UTC (permalink / raw)



Anthony E. Glover wrote in message <37AF0ADE.3D80FEB3@hiwaay.net>...
>Is it possible to re-dispatch a method call within an inherited method?
>For example:
>
>package A defines a type widget that has methods widget_size and
run_widget.
>package B defines a type bigwidget that has an overriding method for
>widget_size, but
>inherits the run_widget method without modification.
>Within package A, run_widget makes a call to widget_size.  Is it
>possbile to force
>a re-dispatch such that the appropriate widget_size method gets called
based
>on the object passed into run_widget?
>
Yes.  You need to type convert the actual parameter in the call to
Widget'Class to make the call a dispatching call.  See RM 95 3.9.2 (1, 5).

As in the example:

with Ada.Text_IO;
package body A is

   procedure Run_Widget (The_Widget : Widget'Class) is
   begin
      Ada.Text_IO.Put_Line
        ("in Run_Widget (The_Widget : Widget): Size =" &
         Positive'Image (Widget_Size (Widget'Class (The_Widget))));
   end Run_Widget;

   function Widget_Size (The_Widget : Widget) return Positive is
   begin
      return 1;
   end Widget_Size;

end A;


package A is
   type Widget is tagged null record;
   procedure Run_Widget (The_Widget : Widget'Class);
   function Widget_Size (The_Widget : Widget) return Positive;
end A;

package body B is
   function Widget_Size (The_Widget : BigWidget) return Positive is
   begin
      return 10;
   end Widget_Size;
end B;

with A;
package B is
   type BigWidget is new A.Widget with null record;
   function Widget_Size (The_Widget : BigWidget) return Positive;
end B;

with A;
with B;
procedure Glover is

   The_Widget : A.Widget;
   The_BigWidget : B.BigWidget;

begin

   A.Run_Widget (The_Widget);
   A.Run_Widget (The_BigWidget);

end Glover;










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

* How to?: Re-dispatching within an inherited method
@ 1999-08-09  0:00 Anthony E. Glover
  1999-08-09  0:00 ` David C. Hoos, Sr.
  0 siblings, 1 reply; 8+ messages in thread
From: Anthony E. Glover @ 1999-08-09  0:00 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 541 bytes --]

Is it possible to re-dispatch a method call within an inherited method?
For example:

package A defines a type widget that has methods widget_size and run_widget.
package B defines a type bigwidget that has an overriding method for
widget_size, but
inherits the run_widget method without modification.
Within package A, run_widget makes a call to widget_size.  Is it
possbile to force
a re-dispatch such that the appropriate widget_size method gets called based
on the object passed into run_widget?

Thanks for any help,
Tony
aeg@hiwaay.net

[-- Attachment #2: Card for Anthony E. Glover --]
[-- Type: text/x-vcard, Size: 361 bytes --]

begin:vcard 
n:Glover;Anthony E.
tel;fax:256-721-1816
tel;home:256-837-7017
tel;work:256-721-7714 X249
x-mozilla-html:FALSE
url:www.elmco.com
org:ELMCO, Inc.
version:2.1
email;internet:aeg@hiwaay.net
title:Senior Software Engineer
adr;quoted-printable:;;6000 Technology Drive=0D=0ASuite N;Huntsville;AL;35805;USA
x-mozilla-cpt:;1
fn:Anthony E. Glover
end:vcard

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

* Re: How to?: Re-dispatching within an inherited method
  1999-08-09  0:00 ` David C. Hoos, Sr.
@ 1999-08-17  0:00   ` Matthew Heaney
  1999-08-17  0:00     ` David C. Hoos, Sr.
  0 siblings, 1 reply; 8+ messages in thread
From: Matthew Heaney @ 1999-08-17  0:00 UTC (permalink / raw)


In article <7onk8f$2qg@hobbes.crc.com> , "David C. Hoos, Sr." 
<david.c.hoos.sr@ada95.com> wrote:

> Yes.  You need to type convert the actual parameter in the call to
> Widget'Class to make the call a dispatching call.  See RM 95 3.9.2 (1, 5).
>
> As in the example:
>
> with Ada.Text_IO;
> package body A is
>
>    procedure Run_Widget (The_Widget : Widget'Class) is
>    begin
>       Ada.Text_IO.Put_Line
>         ("in Run_Widget (The_Widget : Widget): Size =" &
>          Positive'Image (Widget_Size (Widget'Class (The_Widget))));

Did you really mean to declare the formal parameter The_Widget in operation
Run_Widget as having type Widget'Class?  If so, then there's no need for
your explicit conversion of The_Widget to type Widget'Class, because that's
already its type.

The other problem with this solution is that Run_Widget is no longer
primitive, because it takes a class-wide parameter.  The operation is NOT
inherited during derivation.

I suspect that what you really meant was

  procedure Run_Widget (The_Widget : Widget) is
  begin
    ... Widget_Size (Widget'Class (The_Widget)) ...
  end;


>    end Run_Widget;
>
>    function Widget_Size (The_Widget : Widget) return Positive is
>    begin
>       return 1;
>    end Widget_Size;
>
> end A;
>
>
> package A is
>    type Widget is tagged null record;
>    procedure Run_Widget (The_Widget : Widget'Class);

I think you want this:

  procedure Run_Widget (The_Widget : Widget);


>    function Widget_Size (The_Widget : Widget) return Positive;
> end A;
>
> package body B is
>    function Widget_Size (The_Widget : BigWidget) return Positive is
>    begin
>       return 10;
>    end Widget_Size;
> end B;
>
> with A;
> package B is
>    type BigWidget is new A.Widget with null record;
>    function Widget_Size (The_Widget : BigWidget) return Positive;
> end B;
>
> with A;
> with B;
> procedure Glover is
>
>    The_Widget : A.Widget;
>    The_BigWidget : B.BigWidget;
>
> begin
>
>    A.Run_Widget (The_Widget);
>    A.Run_Widget (The_BigWidget);

With the change, you can say:

  B.Run_Widget (The_BigWidget);

and all is well.

> end Glover;

--
Matt

It is impossible to feel great confidence in a negative theory which has
always rested its main support on the weak points of its opponent.

Joseph Needham, "A Mechanistic Criticism of Vitalism"




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

* Re: How to?: Re-dispatching within an inherited method
  1999-08-17  0:00   ` Matthew Heaney
@ 1999-08-17  0:00     ` David C. Hoos, Sr.
  1999-08-18  0:00       ` Matthew Heaney
  0 siblings, 1 reply; 8+ messages in thread
From: David C. Hoos, Sr. @ 1999-08-17  0:00 UTC (permalink / raw)



Matthew Heaney <matthew_heaney@acm.org> wrote in message
news:37b9a823@news1.us.ibm.net...
> In article <7onk8f$2qg@hobbes.crc.com> , "David C. Hoos, Sr."
> <david.c.hoos.sr@ada95.com> wrote:
>
> > Yes.  You need to type convert the actual parameter in the call to
> > Widget'Class to make the call a dispatching call.  See RM 95 3.9.2 (1,
5).
> >
> > As in the example:
> >
> > with Ada.Text_IO;
> > package body A is
> >
> >    procedure Run_Widget (The_Widget : Widget'Class) is
> >    begin
> >       Ada.Text_IO.Put_Line
> >         ("in Run_Widget (The_Widget : Widget): Size =" &
> >          Positive'Image (Widget_Size (Widget'Class (The_Widget))));
>
> Did you really mean to declare the formal parameter The_Widget in
operation
> Run_Widget as having type Widget'Class?  If so, then there's no need for
> your explicit conversion of The_Widget to type Widget'Class, because
that's
> already its type.
>
> The other problem with this solution is that Run_Widget is no longer
> primitive, because it takes a class-wide parameter.  The operation is NOT
> inherited during derivation.
>
> I suspect that what you really meant was
>
>   procedure Run_Widget (The_Widget : Widget) is
>   begin
>     ... Widget_Size (Widget'Class (The_Widget)) ...
>   end;
>
>
Well... I really did mean to make Run_Widget class-wide.  This
may not have beeen consistent with the posting's subject line,
however.

Without completely redesigning the type hierarchy (I would
probably have made Widget abstract, and gone from there),
I was trying to get at the dispatching issue.

And... yes, having made Run_Widget class-wide, the type
conversion is unneccessary.

Without a class-wide Run_Widget, however, the call to
Run_Widget with an actual parameter of type BigWidget is
illegal -- a type conversion is required there.

> >    end Run_Widget;
> >
> >    function Widget_Size (The_Widget : Widget) return Positive is
> >    begin
> >       return 1;
> >    end Widget_Size;
> >
> > end A;
> >
> >
> > package A is
> >    type Widget is tagged null record;
> >    procedure Run_Widget (The_Widget : Widget'Class);
>
> I think you want this:
>
>   procedure Run_Widget (The_Widget : Widget);
>
>
> >    function Widget_Size (The_Widget : Widget) return Positive;
> > end A;
> >
> > package body B is
> >    function Widget_Size (The_Widget : BigWidget) return Positive is
> >    begin
> >       return 10;
> >    end Widget_Size;
> > end B;
> >
> > with A;
> > package B is
> >    type BigWidget is new A.Widget with null record;
> >    function Widget_Size (The_Widget : BigWidget) return Positive;
> > end B;
> >
> > with A;
> > with B;
> > procedure Glover is
> >
> >    The_Widget : A.Widget;
> >    The_BigWidget : B.BigWidget;
> >
> > begin
> >
> >    A.Run_Widget (The_Widget);
> >    A.Run_Widget (The_BigWidget);
>
> With the change, you can say:
>
>   B.Run_Widget (The_BigWidget);
>
> and all is well.
>
> > end Glover;
>
> --
> Matt
>
> It is impossible to feel great confidence in a negative theory which has
> always rested its main support on the weak points of its opponent.
>
> Joseph Needham, "A Mechanistic Criticism of Vitalism"






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

* Re: How to?: Re-dispatching within an inherited method
  1999-08-17  0:00     ` David C. Hoos, Sr.
@ 1999-08-18  0:00       ` Matthew Heaney
  1999-08-18  0:00         ` Anthony E. Glover
  0 siblings, 1 reply; 8+ messages in thread
From: Matthew Heaney @ 1999-08-18  0:00 UTC (permalink / raw)


In article <7pcar9$aeg@hobbes.crc.com> , "David C. Hoos, Sr." 
<david.c.hoos.sr@ada95.com> wrote:

> Without a class-wide Run_Widget, however, the call to
> Run_Widget with an actual parameter of type BigWidget is
> illegal -- a type conversion is required there.
>

Yes, but that's because you used expanded name notation:

  A.Run_Widget (The_BigWidget);  -- illegal

If you want to call the version of the operation that's primitive for
BigWidget, then you have to name the correct operation:

  B.Run_Widget (The_BigWidget);

No type conversion is required.

>> With the change, you can say:
>>
>>   B.Run_Widget (The_BigWidget);
>>
>> and all is well.
--
Matt

It is impossible to feel great confidence in a negative theory which has
always rested its main support on the weak points of its opponent.

Joseph Needham, "A Mechanistic Criticism of Vitalism"




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

* Re: How to?: Re-dispatching within an inherited method
  1999-08-18  0:00       ` Matthew Heaney
@ 1999-08-18  0:00         ` Anthony E. Glover
  1999-08-19  0:00           ` Matthew Heaney
  0 siblings, 1 reply; 8+ messages in thread
From: Anthony E. Glover @ 1999-08-18  0:00 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 1416 bytes --]

In my case, I am using pointers to objects; so, I actually have to
'use' all derived type packages and then make the procedure call
without full dot notation, such as:

use A;
use B;

...
...

    Run_Widget( UnknownWidget.all );

Where UnknownWidget is a pointer to the class wide type.
Is there a better way of doing this?  If I add a new
package with another derived type, then I have to go
add 'uses' to all packages that make calls to methods
of the class.

Tony


Matthew Heaney wrote:
> 
> In article <7pcar9$aeg@hobbes.crc.com> , "David C. Hoos, Sr."
> <david.c.hoos.sr@ada95.com> wrote:
> 
> > Without a class-wide Run_Widget, however, the call to
> > Run_Widget with an actual parameter of type BigWidget is
> > illegal -- a type conversion is required there.
> >
> 
> Yes, but that's because you used expanded name notation:
> 
>   A.Run_Widget (The_BigWidget);  -- illegal
> 
> If you want to call the version of the operation that's primitive for
> BigWidget, then you have to name the correct operation:
> 
>   B.Run_Widget (The_BigWidget);
> 
> No type conversion is required.
> 
> >> With the change, you can say:
> >>
> >>   B.Run_Widget (The_BigWidget);
> >>
> >> and all is well.
> --
> Matt
> 
> It is impossible to feel great confidence in a negative theory which has
> always rested its main support on the weak points of its opponent.
> 
> Joseph Needham, "A Mechanistic Criticism of Vitalism"

[-- Attachment #2: Card for Anthony E. Glover --]
[-- Type: text/x-vcard, Size: 361 bytes --]

begin:vcard 
n:Glover;Anthony E.
tel;fax:256-721-1816
tel;home:256-837-7017
tel;work:256-721-7714 X249
x-mozilla-html:FALSE
url:www.elmco.com
org:ELMCO, Inc.
version:2.1
email;internet:aeg@hiwaay.net
title:Senior Software Engineer
adr;quoted-printable:;;6000 Technology Drive=0D=0ASuite N;Huntsville;AL;35805;USA
x-mozilla-cpt:;1
fn:Anthony E. Glover
end:vcard

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

* Re: How to?: Re-dispatching within an inherited method
  1999-08-18  0:00         ` Anthony E. Glover
@ 1999-08-19  0:00           ` Matthew Heaney
  1999-08-21  0:00             ` Anthony E. Glover
  0 siblings, 1 reply; 8+ messages in thread
From: Matthew Heaney @ 1999-08-19  0:00 UTC (permalink / raw)


In article <37BB74A8.F35560F7@hiwaay.net> , "Anthony E. Glover" 
<aeg@hiwaay.net> wrote:

> In my case, I am using pointers to objects;

Just out of curiosity: why are you using pointers?

Ada was designed so that heap use is often not necessary.  (I just want to
make sure you were aware of this, so you don't inculcate any bad habits.)

> so, I actually have to 'use' all derived type packages and then make the
> procedure call without full dot notation, such as:
>
> use A;
> use B;
>
> ...
> ...
>
>     Run_Widget( UnknownWidget.all );
>
> Where UnknownWidget is a pointer to the class wide type. Is there a better way
> of doing this?

I not convinced you really need to do this.  You don't have to with all the
packages that override primitive operations, if the parameter has a
class-wide type.

The following should work (please test this):

  A.Run_Widget (UnknownWidget.all);


One alternative (that I'm not convinced is necessary) is to make Run_Widget
a class-wide operation (a "template method"), that is implemented by calling
a private primitive operation that dispatches on the tag of the parameter.
For example:

  package P is

    type A is tagged null record;  -- or tagged private

    procedure Run_Widget (O : in out A'Class);  -- class-wide

  private

    procedure Do_Run_Widget (O : in out A);  -- primitive (and private)

  end P;


  package body P is

    procedure Run_Widget (O : in out A'Class) is
    begin
      Do_Run_Widget (O);  -- dispatches on tag of O
    end;

    procedure Do_Run_Widget (O : in out A) is
    begin
      <implementation for type A>
    end;

  end P;


  package P.Q is

    type B is new A with null record;

  private

    procedure Do_Run_Widget (O : in out B);  -- override primitive op

  end P.Q;


  package body P.Q is

    procedure Do_Run_Widget (O : in out B) is
    begin
      <implementation for type B>
    end;

  end P.Q;


Now, there is only one (public) Run_Widget operation.  When you call it:

  A.Run_Widget (UnknownWidget.all);

the internal call to Do_Run_Widget will dispatch on the tag of the param.

I you have a basic algorithm that's that same for all implementations of an
operation -- only parts on it changed based in the specific type -- then a
class-wide operation ("template method") is the way to go.

But if each overriding of the operation has a completely different
implementation, then the operation should just be a simple, public primitive
operation.

I know it must seem weird to say:

  A.Run_Widget (UnknownWidget.all);

and "really" be calling B.Run_Widget, or C.Run_Widget, but that's the nature
of the dispatching mechanism.


> If I add a new package with another derived type, then I have to go add 'uses'
> to all packages that make calls to methods of the class.

No, I don't think so: not if the object has a class-wide type.

If you want more information about template methods, so my posts to the ACM
patterns archive.

<http://www.acm.org/archives/patterns.html>

--
Matt

It is impossible to feel great confidence in a negative theory which has
always rested its main support on the weak points of its opponent.

Joseph Needham, "A Mechanistic Criticism of Vitalism"




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

* Re: How to?: Re-dispatching within an inherited method
  1999-08-19  0:00           ` Matthew Heaney
@ 1999-08-21  0:00             ` Anthony E. Glover
  0 siblings, 0 replies; 8+ messages in thread
From: Anthony E. Glover @ 1999-08-21  0:00 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 3795 bytes --]

Matthew Heaney wrote:
> 
> In article <37BB74A8.F35560F7@hiwaay.net> , "Anthony E. Glover"
> <aeg@hiwaay.net> wrote:
> 
> > In my case, I am using pointers to objects;
> 
> Just out of curiosity: why are you using pointers?
> 
> Ada was designed so that heap use is often not necessary.  (I just want to
> make sure you were aware of this, so you don't inculcate any bad habits.)


The reason I am using pointers is because I have varying number of
widgets and types of widgets that are stored and used by another
piece of code; therefore, I store the pointers to the widgets in
a list.  I can then iterate over the list and perform processing
using the dispatched methods without having to add if checks to
my main processing.  Pointers were the suggested method for 
achieving this based upon the Ada95 Barnes book I was reading.


> 
> > so, I actually have to 'use' all derived type packages and then make the
> > procedure call without full dot notation, such as:
> >
> > use A;
> > use B;
> >
> > ...
> > ...
> >
> >     Run_Widget( UnknownWidget.all );
> >
> > Where UnknownWidget is a pointer to the class wide type. Is there a better way
> > of doing this?
> 
> I not convinced you really need to do this.  You don't have to with all the
> packages that override primitive operations, if the parameter has a
> class-wide type.
> 
> The following should work (please test this):
> 
>   A.Run_Widget (UnknownWidget.all);
> 

I will give it a try.


> One alternative (that I'm not convinced is necessary) is to make Run_Widget
> a class-wide operation (a "template method"), that is implemented by calling
> a private primitive operation that dispatches on the tag of the parameter.
> For example:
> 
>   package P is
> 
>     type A is tagged null record;  -- or tagged private
> 
>     procedure Run_Widget (O : in out A'Class);  -- class-wide
> 
>   private
> 
>     procedure Do_Run_Widget (O : in out A);  -- primitive (and private)
> 
>   end P;
> 
>   package body P is
> 
>     procedure Run_Widget (O : in out A'Class) is
>     begin
>       Do_Run_Widget (O);  -- dispatches on tag of O
>     end;
> 
>     procedure Do_Run_Widget (O : in out A) is
>     begin
>       <implementation for type A>
>     end;
> 
>   end P;
> 
>   package P.Q is
> 
>     type B is new A with null record;
> 
>   private
> 
>     procedure Do_Run_Widget (O : in out B);  -- override primitive op
> 
>   end P.Q;
> 
>   package body P.Q is
> 
>     procedure Do_Run_Widget (O : in out B) is
>     begin
>       <implementation for type B>
>     end;
> 
>   end P.Q;
> 
> Now, there is only one (public) Run_Widget operation.  When you call it:
> 
>   A.Run_Widget (UnknownWidget.all);
> 
> the internal call to Do_Run_Widget will dispatch on the tag of the param.
> 
> I you have a basic algorithm that's that same for all implementations of an
> operation -- only parts on it changed based in the specific type -- then a
> class-wide operation ("template method") is the way to go.
> 
> But if each overriding of the operation has a completely different
> implementation, then the operation should just be a simple, public primitive
> operation.
> 
> I know it must seem weird to say:
> 
>   A.Run_Widget (UnknownWidget.all);
> 
> and "really" be calling B.Run_Widget, or C.Run_Widget, but that's the nature
> of the dispatching mechanism.
> 
> > If I add a new package with another derived type, then I have to go add 'uses'
> > to all packages that make calls to methods of the class.
> 
> No, I don't think so: not if the object has a class-wide type.
> 
> If you want more information about template methods, so my posts to the ACM
> patterns archive.
> 
> <http://www.acm.org/archives/patterns.html>

I will digest these comments some more when I get back to work.

Thanks for the reply,
Tony

[-- Attachment #2: Card for Anthony E. Glover --]
[-- Type: text/x-vcard, Size: 361 bytes --]

begin:vcard 
n:Glover;Anthony E.
tel;fax:256-721-1816
tel;home:256-837-7017
tel;work:256-721-7714 X249
x-mozilla-html:FALSE
url:www.elmco.com
org:ELMCO, Inc.
version:2.1
email;internet:aeg@hiwaay.net
title:Senior Software Engineer
adr;quoted-printable:;;6000 Technology Drive=0D=0ASuite N;Huntsville;AL;35805;USA
x-mozilla-cpt:;1
fn:Anthony E. Glover
end:vcard

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

end of thread, other threads:[~1999-08-21  0:00 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1999-08-09  0:00 How to?: Re-dispatching within an inherited method Anthony E. Glover
1999-08-09  0:00 ` David C. Hoos, Sr.
1999-08-17  0:00   ` Matthew Heaney
1999-08-17  0:00     ` David C. Hoos, Sr.
1999-08-18  0:00       ` Matthew Heaney
1999-08-18  0:00         ` Anthony E. Glover
1999-08-19  0:00           ` Matthew Heaney
1999-08-21  0:00             ` Anthony E. Glover

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