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.8 required=5.0 tests=BAYES_00,INVALID_DATE autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 109fba,66253344eaef63db X-Google-Attributes: gid109fba,public X-Google-Thread: 1108a1,66253344eaef63db X-Google-Attributes: gid1108a1,public X-Google-Thread: 103376,66253344eaef63db X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 1994-09-30 07:06:35 PST Path: bga.com!news.sprintlink.net!howland.reston.ans.net!math.ohio-state.edu!jussieu.fr!univ-lyon1.fr!swidir.switch.ch!epflnews!dinews.epfl.ch!di.epfl.ch!Magnus.Kempe From: Magnus.Kempe@di.epfl.ch (Magnus Kempe) Newsgroups: comp.lang.ada,comp.object,comp.lang.c++ Subject: Re: Mut. Recurs. in Ada9X w/o Breaking Encaps.? (LONG) Date: 29 Sep 1994 13:10:03 GMT Organization: Ecole Polytechnique Federale de Lausanne Distribution: world Message-ID: <36eebb$jn5@disunms.epfl.ch> References: <1994Sep27.165203.9192@swlvx2.msd.ray.com> <36bt0c$17oo@watnews1.watson.ibm.com> <1994Sep29.103358@di.epfl.ch> NNTP-Posting-Host: lglsun4.epfl.ch Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8bit Keywords: Ada 9X, C++, object-oriented Xref: bga.com comp.lang.ada:6329 comp.object:6911 comp.lang.c++:31077 Date: 1994-09-29T13:10:03+00:00 List-Id: John is still not satisfied that Ada 9X has a clean, elegant solution to his problem (two abstractions, Employee and Office, have a recursive dependency--how to model/implement that?). The example below illustrates that Ada 9X allows you to easily model/ implement abstractions and their relationships--while enforcing and preserving the concomitant encapsulations. That's what I call progress! (Yes, this all compiles with GNAT, a.k.a. "GNU Ada".) As I wrote in an other message: -- Since this couple of recursive types is strictly internal to the -- abstraction "employee and his office", I recommend that they be -- declared as abstract and hidden in the private part of the parent -- package. -------------------------------------------------------------------- package Company is -- This subsystem exports two abstractions, Employee and Office, which -- are mutually dependent (in a symmetric, one-to-one relationship). private -- the following private declarations set up the 1-1 relationship type Employee_Parent; type Employee_Reference is access all Employee_Parent'Class; type Office_Parent; type Office_Reference is access all Office_Parent'Class; type Employee_Parent is abstract tagged record Its_Occupied_Office : Office_Reference; end record; type Office_Parent is abstract tagged record Its_Occupying_Employee : Employee_Reference; end record; end Company; -- We now declare both abstractions in child units (based on Norm's solution) ----------------------------------------------------------------------------- with ... ; -- other stuff needed by Employee package Company.Employees is type Employee is private; type Employee_Pointer is access all Employee; No_Employee : constant Employee_Pointer := null; ... -- Employee subprograms involving that "other stuff" private type Employee is new Employee_Parent with record ... -- various components involving that "other stuff" end record; end Company.Employees; with ... ; -- other stuff needed by Office package Company.Offices is type Office is private; type Office_Pointer is access all Office; No_Office : constant Office_Pointer := null; ... -- Office subprograms involving that "other stuff" private type Office is new Office_Parent with record ... -- various components involving that "other stuff" end record; end Company.Offices; -- we can now declare operations working with both abstractions --------------------------------------------------------------- with Company.Employees, Company.Offices; package Company.Common is function Office_Occupied_By (The_Employee : in Employees.Employee) return Offices.Office_Pointer; function Employee_Occupying (The_Office : in Offices.Office) return Employees.Employee_Pointer; procedure Occupy (The_Office : in Offices.Office_Pointer; The_Employee : in Employees.Employee_Pointer); ... -- Employee and Office subprograms working with the relationship -- and/or the operations exported by each abstraction. end Company.Common; -- Note that the exported pointers are "specific". The client does not -- see anything class-wide. John Volan is afraid that we will have -- recourse to "Unchecked_Conversion" and/or break Ada's type safety. -- Not at all. We need a private child, but that's part of building -- clean subsystems. ----------------------------------------------------------------------- private package Company.Employees.Ptrs is -- helper package which "knows" that Employee is derived from Employee_Parent function Office_of (The_Employee : in Employee) return Office_Reference; end Company.Employees.Ptrs; package body Company.Employees.Ptrs is function Office_of (The_Employee : in Employee) return Office_Reference is begin return The_Employee.Its_Occupied_Office; end Office_of; end Company.Employees.Ptrs; with Company.Employees.Ptrs; package body Company.Common is function Office_Occupied_By (The_Employee : in Employees.Employee) return Offices.Office_Pointer is begin return Offices.Office_Pointer (Employees.Ptrs.Office_of (The_Employee)); -- the type conversion (from one access type to another) involves -- a type check: is the designated object of type Offices.Office? -- If not, exception Constraint_Error will be raised. end Office_Occupied_By; -- similar approach for Employee_Occupying and Occupy ... end Company.Common; -- John Volan expects that the body of each abstraction will be a client -- of the other abstraction. No problem. ------------------------------------------------------------------------ with Company.Offices; package body Company.Employees is ... -- bodies of Employee subprograms involving that "other stuff" -- and using the operations exported by Office end Company.Employees; with Company.Employees; package body Company.Offices is ... -- bodies of Office subprograms involving that "other stuff" -- and using the operations exported by Employee end Company.Offices; So... The structure of the system is clearly made for one abstraction Employee and one abstraction Office. A future maintainer cannot accidentally add subclasses of the two abstractions and silently break the common operations. The encapsulation of each abstraction is not broken anywhere; rather, the one-one relationship is abstracted into the parent Company package and operated upon in the child package Company.Common. -- Magnus Kempe "I know not what course others may take, but as for me, Magnus.Kempe@di.epfl.ch Give me Liberty... or give me Death!" -- Patrick Henry PS: the above code needs a work around for a GNAT bug (lack of visibility from a grand-child to his grand-parent). In company-employees.ads amd company-offices.ads, add the following two lines in each private part: subtype Employee_Reference is Company.Employee_Reference; subtype Office_Reference is Company.Office_Reference;