From: Magnus.Kempe@di.epfl.ch (Magnus Kempe)
Subject: Re: Mut. Recurs. in Ada9X w/o Breaking Encaps.? (LONG)
Date: 29 Sep 1994 13:10:03 GMT
Date: 1994-09-29T13:10:03+00:00 [thread overview]
Message-ID: <36eebb$jn5@disunms.epfl.ch> (raw)
In-Reply-To: 1994Sep29.103358@di.epfl.ch
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;
next prev parent reply other threads:[~1994-09-29 13:10 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
1994-09-27 16:52 Mut. Recurs. in Ada9X w/o Breaking Encaps.? (LONG) John Volan
1994-09-27 18:48 ` Mark A Biggar
1994-09-29 1:46 ` John Volan
1994-09-29 13:57 ` Tucker Taft
1994-09-29 17:20 ` Bjarne Stroustrup <9758-26353> 0112760
1994-09-30 1:38 ` Tucker Taft
1994-09-30 12:33 ` Bjarne Stroustrup <9758-26353> 0112760
1994-09-29 18:37 ` John Volan
1994-09-29 19:34 ` David Weller
1994-09-30 22:13 ` John Volan
1994-10-02 3:31 ` Andrew Lees
1994-09-30 1:47 ` Tucker Taft
1994-09-30 13:30 ` John Volan
1994-09-29 18:10 ` R. William Beckwith
1994-10-03 0:33 ` Cyrille Comar
1994-09-28 14:01 ` Norman H. Cohen
1994-09-29 2:12 ` John Volan
1994-09-29 14:01 ` Tucker Taft
1994-09-29 18:37 ` Norman H. Cohen
1994-09-29 9:48 ` Magnus Kempe
1994-09-29 13:10 ` Magnus Kempe [this message]
1994-09-29 18:05 ` Tucker Taft
1994-09-30 10:20 ` Mut. Recurs. in Ada9X w/o Breaking Encaps.? Magnus Kempe
1994-09-30 13:22 ` Tucker Taft
1994-10-01 1:24 ` Mut. Recurs. in Ada9X w/o Breaking Encaps.? (LONG) Adam Beneschan
1994-10-01 12:01 ` Magnus Kempe
1994-10-01 18:43 ` Mark A Biggar
1994-10-02 16:41 ` John Volan
1994-10-02 23:33 ` Matt Kennel
1994-10-03 8:07 ` Mut. Recurs. in Ada9X w/o Breaking Encaps.? Magnus Kempe
1994-10-03 12:14 ` Mut. Recurs. in Ada9X w/o Breaking Encaps.? (LONG) Robert I. Eachus
1994-10-04 2:12 ` R. William Beckwith
1994-10-04 16:00 ` John Volan
1994-10-05 11:42 ` Robert I. Eachus
1994-10-05 21:09 ` Matt Kennel
1994-10-03 20:29 ` Harry Koehnemann
1994-09-29 13:35 ` John Volan
1994-09-30 20:27 ` Norman H. Cohen
1994-10-01 1:47 ` John Volan
1994-10-01 20:44 ` Tucker Taft
1994-10-03 11:29 ` Robert I. Eachus
1994-09-30 22:46 ` Matt Kennel
1994-10-01 2:11 ` John Volan
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox