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=-1.9 required=5.0 tests=BAYES_00, T_FILL_THIS_FORM_SHORT autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 109fba,9ac62ca34a465706 X-Google-Attributes: gid109fba,public X-Google-Thread: 103376,9ac62ca34a465706 X-Google-Attributes: gid103376,public From: eachus@spectre.mitre.org (Robert I. Eachus) Subject: Re: on OO differnces between Ada95 and C++ Date: 1996/02/20 Message-ID: X-Deja-AN: 140492814 references: <4gbq7q$g08@qualcomm.com> organization: The Mitre Corp., Bedford, MA. newsgroups: comp.lang.ada,comp.lang.c++ Date: 1996-02-20T00:00:00+00:00 List-Id: In article <4gbq7q$g08@qualcomm.com> nabbasi@qualcomm.com (Nasser Abbasi) writes: > I have been playing around with the OO features in Ada95 and > comparing it with C++. I noticed this little difference, and I'd > like to see what you think of it... > In C++, the client to the saving_account class can also use the > Money_Type type (even though that is defined in the base class > Account) without having to include base class "account.h", this is > because Money_Type has become a public part of the Saving_Account > class when Saving_Account inherited Saving class. Not quite true. The visibility is because the copy semantics associated with #include are transitive. Anyone who includes saving_account also copies account, and in fact the "standard" C idiom of defining a global and testing it around #includes is to avoid including multiple copies. > In Ada95, the client of Saving_Account has no viability to Money_Type > type definition even though they with'ed Saving_account package, since > Money_Type is not a "inherited" by the Saving_Account package > from the Account package. Again it is a little more complex than that. In Ada 95 the type is in scope throughout all of the semantic dependents, but the name of the type or of its operations is visible in a subset of that range. In any case there are several different ways of making visible (or directly visible) the name and operations of Money_Type. > This means that in Ada95, If one wants to access things like type > definitions that are not tagged, but used in defining components > inside the tagged record, one must "with" the client package and > also packages that the client package with'ed just to be able to > have viability to those type definitions. No, another solution is to re-export them from Saving_Account. That is seldom the right solution in Ada, and is probably not right here. > In this case, It seems the C++ way of having everything inside the > public base class becoming visible to clients of the derived class > that inherits the base class is more economical?. > ...Any better way? Yes, 1) restructure your program to use child packages: ----------------- accounting.ads package Accounting is type Money_Type is delta 0.01 digits 9; -- just my example ;-) type Account_Id is private; private type Account_Id is new Integer; end Accounting; ------------------ account.ads --------------------------- package Accounting.Account is type Account_Type is tagged private; -- operations on type Account_Type defined here including procedure Set_Balance(A: Account, M: Accounting.Money_Type); private function New_Account_ID return Account_ID; type Account_Type is tagged record Balance : Money_Type := 0.0; Id : Account_Id := New_Account_ID; end record; end Account; ----------------- saving_account.ads ---------------- with Accounting.Account; package Saving_Account is type Saving_Account_Type is new Account.Account_Type with private; -- new operations on savings accounts defined here including private type Saving_Account_Type is new Account.Account_Type with record Interest : Account.Money_Type; end record; end Saving_Account; --------------- main.adb --------------------------- with Accounting.Saving_Account; -- with of Accounting is implicit, with of Accounting.Acount unneeded. with Ada.Text_IO; use Ada.Text_IO; procedure main is package Money_IO is new Ada.Text_IO.Decimal_IO(Accounting.Money_Type); The_Saving_Account : Saving_Account.Saving_Account_Type; The_Balance : Accounting.Money_Type; begin Money_IO.Get(The_Balance); Set_Balance(The_Saving_Account, The_Balance); end Main; I added the use of private parts to emphasize the way this works. The operations declared explicitly or implicitly within the private part of Accounting are visible within the children of Accounting as well. So I could, if I wanted, hide the full declaration of Money_Type, and the instantiation of Money_IO within the private part of Accounting, and explicitly export operations which do IO from Accounting.Account. Of course this would implicitly define the same operations for Saving_Account and/or I could add additional IO operations. All in all a bit heavy for such a small example. But in larger programs, you find yourself pushing for information hiding wherever possible. -- Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is...