comp.lang.ada
 help / color / mirror / Atom feed
From: ncohen@watson.ibm.com (Norman H. Cohen)
Subject: Re: Mut. Recurs. in Ada9X w/o Breaking Encaps.? (LONG)
Date: 29 Sep 1994 18:37:19 GMT
Date: 1994-09-29T18:37:19+00:00	[thread overview]
Message-ID: <36f1gv$hln@watnews1.watson.ibm.com> (raw)
In-Reply-To: 1994Sep29.021209.20769@swlvx2.msd.ray.com

In article <1994Sep29.021209.20769@swlvx2.msd.ray.com>,
jgv@swl.msd.ray.com (John Volan) writes: 

|> This solution suffers from the same problem as Mark Biggar's suggestion: 

Mark's solution and mine have a lot in common.  (I should have declared
Employee_Parent and Office_Parent to be abstract, as Mark did with the
corresponding types in his solution, to indicate my intent that there be
no objects of this type.)

|> These access types only give clients an "opaque" view of the designated objects.
|> The useful primitive operations for these objects won't be declared until we
|> get to the concrete *subclasses* declared later.  So a client would have to
|> resort to using a non-typesafe Unchecked_Conversion to "downcast" one of these
|> pointers into designating the corresponding concrete subclass.

You are right.  This problem can be solved by declaring all the
operations of Employee and Office as abstract operations of
Employee_Parent and Office_Parent.  (So making the parent types abstract
isn't just a good idea, it's the law.)  The common operations can be
handled by adding

    function Office_Occupied_By (The_Employee : in Employee_Parent'Class)
      return Office_Pointer;

    function Employee_Occupying (The_Office : in Office_Parent'Class)
      return Employee_Pointer;

    procedure Occupy (The_Office   : in access Office_Parent'Class;
                      The_Employee : in access Employee_Parent'Class);

to Employees_And_Offices as concrete classwide operations.

|> Another issue is whether the concrete subclasses declared below are going to
|> be the *only* subclasses of these abstract classes.  Certainly that's the
|> original intent -- but will a maintainer pay any attention? ;-)

I don't see any problem here.  If the maintainer can come up with another
useful extension to Office_Parent or Employee_Parent, more power to him.
Indeed, type inheritance and child packages are useful in part as a
"structured" way for a maintenance programmer to tailor the facilities in
the original program in a way not anticipated by the original author,
while leaving the original author's source intact.  The correctness of an
OO program should not depend on the absence of subclasses not mentioned
in the original program!

|> Another problem here is that this doesn't really solve the original puzzle I
|> posed:  How do you avoid breaking encapsulation *between* these two classes?
|> These type declarations are private, but since the packages below are all
|> children of this parent package, they have complete visibility to the private
|> part of the parent.  So an Employee subprogram still has license to ignore
|> the public primitives of the Office class and "diddle" with the Office's
|> private components directly.  (And vice versa.)

What you are asking for is impossible.  As I noted yesterday, there is no
way to define, in two separate packages, two types with primitive
operations that operate on the other type, because the package specs are
not allowed to be mutually dependent: 

   - If Offices depends on Employees, for example, Employees can not depend on
     Offices, so there is no way to declare Office_Occupied_By (which
     must be declared in a place where its body can see the
     Its_Occupied_Office record component).

   - If Offices does not depend on Employees, there is no way to declare
     Employee_Occupying (which must be declared in a place where its body
     can see the Its_Occupying_Employee record component).

But, as the song says, that's what friends are for.  The implementations
of mutually recursive types are often so tightly intertwined that it is
not possible to say where one ends and the other begins; in the case of
tightly coupled mutually recursive types there is no point in hiding the
implementation of one from the implementation of the other.  Tightly
coupled mutually recursive types constitute a single abstraction
consisting of two or more types, typically designed by one person and
implemented by one person even if the abstraction is distributed among
several child packages.  When the mutually recursive types are tightly
coupled, the ability of the subprogram bodies for each type single to
reference the full recursive definition is a feature, not a bug.

However, types Office and Employee are not so intimately intertwined.
Each contains one pointer to the other and much more that has nothing to
do with the other type.  Here is an approach that exploits the loose
coupling between the recursive types to hide only the "other stuff": 

   package Employees_And_Offices is

      type Employee_Parent is abstract tagged private;
      type Employee_Pointer is access all Employee_Parent'Class;
       -- Abstract Employee_Parent subprograms involving that
       --     "other stuff"

       type Office_Parent is abstract tagged private;
       type Office_Pointer is access all Office_Parent'Class;
       -- Abstract Office_Parent subprograms involving that
       --     "other stuff"

       -- Concrete nondispatching subprograms involving only the pointers
       --    between the classes: 

       function Office_Occupied_By
          (The_Employee: in Employee_Parent'Class) return Office_Pointer;

       function Employee_Occupying
          (The_Office: in Office_Parent'Class) return Employee_Pointer;

       procedure Occupy
          (The_Office: in Office_Pointer; The_Employee: in Employee_Pointer);

   private

      -- Only those components of Office and Employee that are of mutual
      --    interest: 

      type Employee_Parent is
         record
            Its_Occupied_Office : Office_Pointer;
         end record;

      type Office_Parent is
         record
            Its_Occupying_Employee : Employee_Pointer;
         end record;

   end Employees_And_Offices;

   package body Employees_And_Offices is

       function Office_Occupied_By
          (The_Employee: in Employee_Parent'Class) return Office_Pointer is
       begin
          return The_Employee.Its_Occupied_Office;
       end Office_Occupied_By;

       function Employee_Occupying
          (The_Office: in Office_Parent'Class) return Employee_Pointer is
       begin
          return The_Office.Its_Occupying_Employee;
       end Employee_Occupying;

       procedure Occupy
          (The_Office: in Office_Pointer; The_Employee: in Employee_Pointer) is
       begin
          The_Employee.Its_Occupied_Office := The_Office;
          The_Office.Its_Occupying_Employee := The_Employee;
       end Occupy;

   end Employees_And_Offices;

   package Employees_And_Offices.Employees is
      type Employee is new Employee_Parent with private;
       -- Concrete Employee subprograms involving that
       --     "other stuff"
   private
      type Employee is new Employee_Parent with
         record
            -- various components involving that "other stuff"
         end record;
   end Employees_And_Offices.Employees;

   package Employees_And_Offices.Offices is
      type Office is new Office_Parent with private;
       -- Concrete Office subprograms involving that
       --     "other stuff"
   private
      type Office is new Office_Parent with
         record
            -- various components involving that "other stuff"
         end record;
   end Employees_And_Offices.Offices;


--
Norman H. Cohen    ncohen@watson.ibm.com



  parent reply	other threads:[~1994-09-29 18:37 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 [this message]
1994-09-29  9:48   ` Magnus Kempe
1994-09-29 13:10     ` Magnus Kempe
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