comp.lang.ada
 help / color / mirror / Atom feed
* C++ virtual function mechanism in Ada ?
@ 2001-07-25 13:15 Didier.pieroux
  2001-07-25 13:43 ` Jean-Pierre Rosen
  2001-07-25 15:49 ` Larry Kilgallen
  0 siblings, 2 replies; 14+ messages in thread
From: Didier.pieroux @ 2001-07-25 13:15 UTC (permalink / raw)


Hi Ada programmers !

I am learning Ada and I have two questions relative to dynamical dispatching. As
the title said, I have a C++ background but, needless to say, I don't want to
start yet another flamewar on the relative merits of both languages... I just
want to improve my Ada understanding. Heu... yes, I should confess it: I don't
have reached the end of any of the Ada books I am reading in parallel yet. So
perhaps I am really missing something obvious :-(

As most of you know, one of the feature of C++ is the virtual function
mechanism.  It allows the right method to be called on an object of a derived
class whenever it is accessed via a pointer or a reference of a base class.  I
was first naively thinking that Ada primitive operations were playing an
equivalent role... but that's not exactly true.  

For instance, consider the following piece of code.  A tagged type T1 is
declared along with 3 primitive operations: E, F and G.  G prints its name and
calls F that prints its name and calls E that prints its name. A type T2 is also
derived from T1 and E and G are overriden. Note that G still calls the
unoverriden F primitive operation:

-- Better use a fixed size font

package Essai is
type T1 is tagged null record;
procedure E(A: in T1);
procedure F(A: in T1);      
procedure G(A: in T1);   

type T2 is new T1 with null record;
procedure E(A: in T2);
procedure G(A: in T2);
end Essai;

with Ada.Text_Io; use Ada.Text_Io;
package body Essai is
procedure E(A: in T1) is begin Put_line("E1");       end E; 
procedure F(A: in T1) is begin Put("F1:");     E(A); end F;
procedure G(A: in T1) is begin Put("G1:");     F(A); end G;

procedure E(A: in T2) is begin Put_Line("E2");       end E;
procedure G(A: in T2) is begin Put("G2:");     F(A); end G;
end Essai;

with Essai; use Essai;
procedure Main is
V2 : T2;
begin
G(V2);
end Main; 

When I run the program, I get: "G2:F1:E1". I understand well that F(...) has a
formal parameter of type T1 and thus the call E(A) in F(...) is statically
bound. So, this output is the correct one from the Ada point of vue, no problem
with that. Nevertheless, what I wanted was "G2:F1:E2", i.e. that the procedure E
of T2 be called !  This is what would happen in C++ by declaring E virtual.

One way to get the job done is to use:
procedure F(A: in T1) is begin Put("F1:");     E(T1'Class(A)); end F;
That switches the dynamical dispatching on and everybody is happy. But the bad
point is that I have the impression that extending a base type can require
modifications in that base type implementation. Too bad for code reliability,
isn't it ?

So, my first question is: knowing that a characteristic feature of primitive
operations is to call them with objects of a derived type, why did the Ada
designers choose not to use dynamical dispatching when calling a primitive
function ?  I guess that most of the time Ada programmers (as C++ programmers)
want to really call the primitive operation corresponding to the type of the
actual parameter, no ?

Second question... In order to simulate the virtual function mechanism for
primitive operation, I found the following solution.  I declare (non-primitive)
procedures with a class-wide formal argument of the Base type. The only thing
they do is to call the real primitive functions. Elsewhere in the code, these
primitive functions are never called directly but always through the class-wide
procedures. Using this, the package above becomes:


package Essai2 is
type T1 is tagged null record;
procedure E(A: in T1'Class);
procedure F(A: in T1'Class);
Procedure G(A: in T1'Class);

procedure xE(A: in T1);
procedure xF(A: in T1);      
procedure xG(A: in T1);   

type T2 is new T1 with null record;
procedure xE(A: in T2);
procedure xG(A: in T2);

end Essai2;

with Ada.Text_Io; use Ada.Text_Io;
package body Essai2 is
procedure E(A: in T1'Class) is begin xE(A); end E;
procedure F(A: in T1'Class) is begin xF(A); end F;
procedure G(A: in T1'Class) is begin xG(A); end G;

procedure xE(A: in T1) is begin Put_line("E1:");       end xE; 
procedure xF(A: in T1) is begin Put("F1:");      E(A); end xF;
procedure xG(A: in T1) is begin Put("G1:");      F(A); end xG;

procedure xE(A: in T2) is begin Put_Line("E2");        end xE;
procedure xG(A: in T2) is begin Put("G2:");      F(A); end xG;
end Essai2;

With this new version of the code, one gets G2:F1:E2 as wanted. 

=> Questions: is it the right way to simulate the C++ virtual mechanism in Ada
or is there something more clever or more "in the Ada approach" ?

Thanks !
Didier





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

end of thread, other threads:[~2001-07-30  8:09 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-07-25 13:15 C++ virtual function mechanism in Ada ? Didier.pieroux
2001-07-25 13:43 ` Jean-Pierre Rosen
2001-07-25 16:10   ` Warren W. Gay VE3WWG
2001-07-25 15:49 ` Larry Kilgallen
2001-07-26  2:00   ` DuckE
2001-07-26  3:14     ` Larry Kilgallen
2001-07-26 10:44       ` Robert Dewar
2001-07-26 12:52         ` Dmitry A. Kazakov
2001-07-26 17:18           ` Ted Dennison
2001-07-28  2:10           ` Robert Dewar
2001-07-30  8:09             ` Dmitry Kazakov
2001-07-26 12:57         ` Larry Kilgallen
2001-07-26 10:38   ` Robert Dewar
2001-07-26 17:31     ` Warren W. Gay VE3WWG

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