comp.lang.ada
 help / color / mirror / Atom feed
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;




  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