From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_00,TO_NO_BRKTS_FROM_MSSP autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,599b13f801b0f9eb,start X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2001-07-25 06:16:15 PST Path: archiver1.google.com!newsfeed.google.com!newsfeed.stanford.edu!feed.textport.net!newsranger.com!www.newsranger.com!not-for-mail Newsgroups: comp.lang.ada From: Didier.pieroux Subject: C++ virtual function mechanism in Ada ? Message-ID: X-Abuse-Info: When contacting newsranger.com regarding abuse please X-Abuse-Info: forward the entire news article including headers or X-Abuse-Info: else we will not be able to process your request X-Complaints-To: abuse@newsranger.com NNTP-Posting-Date: Wed, 25 Jul 2001 09:15:20 EDT Organization: http://www.newsranger.com Date: Wed, 25 Jul 2001 13:15:20 GMT Xref: archiver1.google.com comp.lang.ada:10559 Date: 2001-07-25T13:15:20+00:00 List-Id: 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