comp.lang.ada
 help / color / mirror / Atom feed
From: jgv@swl.msd.ray.com (John Volan)
Subject: Re: Mut. Recurs. in Ada9X w/o Breaking Encaps.? (LONG)
Date: Tue, 4 Oct 1994 16:00:56 GMT
Date: 1994-10-04T16:00:56+00:00	[thread overview]
Message-ID: <1994Oct4.160056.4243@swlvx2.msd.ray.com> (raw)
In-Reply-To: EACHUS.94Oct3121410@spectre.mitre.org

eachus@spectre.mitre.org (Robert I. Eachus) writes:

>This one has a very simple solution: child units.
>This eliminates the "necessity" for mutual recursion in the visible
>package specifications.

>   However, there are limitations to this approach.  (Let me do a bit
>of a sketch here:

>   package Employees is
>     type Employee is tagged private;
>     ...
>   end Employees;

>   package Offices is
>     type Office is tagged private;
>     ...
>   end Offices;

>   with Offices; use Offices;
>   function Employees.Assigned_Office(E: in Employee) return Office;

>   with Employees; use Employees;
>   function Offices.Occupant(O: in Office) return Employee;

This approach is nice, as long as we are willing to give up having
these operations be primitives for their respective tagged types.
I guess the only way I'd expand on this would be to make these into
child packages rather than just child functions.

Also, it looks like this scheme gives up on the possibility of
incorporating the pointers directly into the tagged record types
themselves, since they would still need to be declared in the private
parts of the root packages somehow.  However, this scheme could be
combined very nicely with the approach Matt Kennel suggested of
off-loading the association itself to a third package that implemented
some kind of dual hash-table:

  ----------------------------------------------------------------------
  generic
    type Former (<>) is limited private;
    type Former_Pointer is access all Object'Class;
    type Latter (<>) is limited private;
    type Latter_Pointer is access all Object'Class;
  package One_To_One is

    function Latter_Of (The_Former : in Former_Pointer) return Latter_Pointer;
    function Former_Of (The_Latter : in Latter_Pointer) return Former_Pointer;

    procedure Associate
    ( The_Former : in Former_Pointer;
      The_Latter : in Latter_Pointer );

    procedure Dissociate
    ( The_Former : in Former_Pointer );

    procedure Dissociate
    ( The_Latter : in Latter_Pointer );

  end One_To_One;

  -- Implementation of this is left as an exercise for the reader ... :-)

  ----------------------------------------------------------------------

  with Employee;
  with Office;
  with One_To_One;
  package Employee_Occupies_Office is new 
    One_To_One (Former         => Employee.Object,
                Former_Pointer => Employee.Pointer,
                Latter         => Office.Object,
                Latter_Pointer => Office.Pointer);

  ----------------------------------------------------------------------

  with Office;
  with Employee_Occupies_Office;
  package Employee.Office_Occupied is

    -- Employee.Office_Occupied.That_Of
    function That_Of 
    ( The_Employee : in Employee.Object'Class ) return Office.Pointer;

    -- Employee.Office_Occupied.Associate 
    procedure Associate
    ( The_Employee : in out Employee.Object'Class;
      New_Office   : in     Office.Pointer );

    -- Employee.Office_Occupied.Dissociate
    procedure Dissociate
    ( The_Employee : in out Employee.Object'Class );

  end Employee.Office_Occupied;

  ----------------------------------------------------------------------

  package body Employee.Office_Occupied is

    -- Employee.Office_Occupied.That_Of
    function That_Of 
    ( The_Employee : in Employee.Object'Class ) return Office.Pointer is
    begin
      Employee_Occupies_Office.Latter_Of (The_Former => The_Employee'Access);
    end That_Of;

    -- Employee.Office_Occupied.Associate 
    procedure Associate
    ( The_Employee : in out Employee.Object'Class;
      New_Office   : in     Office.Pointer ) is
    begin
      Employee_Occupies_Office.Associate
      ( The_Former => The_Employee'Access,
        The_Latter => New_Office );
    end Associate;

    -- Employee.Office_Occupied.Dissociate
    procedure Dissociate
    ( The_Employee : in out Employee.Object'Class ) is
    begin
      Employee_Occupies_Office.Dissociate (The_Former => The_Employee'Access);
    end Dissociate;

  end Employee.Office_Occupied;

  ----------------------------------------------------------------------

  with Employee;
  with Employee_Occupies_Office;
  package Office.Employee_Occupant is

    -- Office.Employee_Occupant.That_Of
    function That_Of
    ( The_Office : in Office.Object'Class ) return Employee.Pointer;

     -- Office.Employee_Occupant.Associate
     procedure Associate
     ( The_Office   : in out Office.Object'Class;
       New_Employee : in     Employee.Pointer );

     -- Office.Employee_Occupant.Dissociate
     procedure Dissociate
     ( The_Employee : in out Employee.Object'Class );

  end Office.Employee_Occupant;

  ----------------------------------------------------------------------

  package body Office.Employee_Occupant is

    -- Office.Employee_Occupant.That_Of
    function That_Of 
    ( The_Office : in Office.Object'Class ) return Employee.Pointer is
    begin
      Employee_Occupies_Office.Former_Of (The_Latter => The_Office'Access);
    end That_Of;

    -- Office.Employee_Occupant.Associate 
    procedure Associate
    ( The_Office   : in out Office.Object'Class;
      New_Employee : in     Employee.Pointer ) is
    begin
      Employee_Occupies_Office.Associate
      ( The_Latter => The_Office'Access,
        The_Former => New_Employee );
    end Associate;

    -- Office.Employee_Occupant.Dissociate
    procedure Dissociate
    ( The_Office : in out Office.Object'Class ) is
    begin
      Employee_Occupies_Office.Dissociate (The_Latter => The_Office'Access);
    end Dissociate;

  end Office.Employee_Occupant;

  ----------------------------------------------------------------------

I guess the real philosophical issue that everything is hinging on
here is: "Is a binary association *part* of the abstraction of each of
the classes, or is it a *separate* abstraction of its own?"

Adam Beneschan objected to other solutions that put the association
structure in a common root package, on the grounds that nothing from
the "real world" was being modeled by that.  I disagree with that, and
agree with Magnus Kempe that in fact the association should be treated
as a first-class abstraction of its own, in some fashion.  However, I
do not agree with Magnus Kempe that those other solutions "perfectly"
implement this abstraction, because of the coupling that I see them
introducing.  If you want to avoid that coupling, then I think that
two child packages hanging off of the associated root class packages,
and/or a separate package entirely, would be better solutions.

But a corollary to this issue is the question: "Do association
operations *need* to be primitives of each of the associated classes?"
I'm beginning to think not, but I'm not sure I have a good handle on
this question yet.  Any thoughts?

>   As sketched, this provides a clean, clear interface.  However there
>are two problems.  First, there is going to have to be some
>abstraction breaking to implement the bodies of these units.  It can
>be done in a type safe manner, with private child units, and there are
>other possibilities.

I'm not sure what you mean by "abstraction breaking".  Is there some
trick we could use to get those pointers into the tagged records after all?
Perhaps "opaque" forms of the pointers that somehow get converted to
"transparent" forms later?

>   Second, these functions are not inheritable, so you might want:
>
>   with Offices; use Offices;
>   function Employees.Assigned_Office(E: in Employee'CLASS)
>        return Office'CLASS;
>
>   with Employees; use Employees;
>   function Offices.Occupant(O: in Office'CLASS) return Employee'CLASS;
>
>   instead of the versions above.  

Yes, I believe I drew the same conclusion early on, that these would
be class-wide, non-dispatching operations, even if they could somehow
be placed in the root package.  I think it's reasonable to assume that
a Rumbaugh-style association should apply equivalently to all
instances of a class and its subclasses

>Since such subprograms would have
>to deal with all of the (possibly) many subclasses to employees or
>offices, this approach can result in unmaintainable code. However for
>small projects, or for attributes which are orthogonal to the rest of
>the abstraction, this approach works just fine.

I don't think there's any problem here. It seems to me the most
reasonable interpretation of a Rumbaugh-style Object Model would not
allow subclasses to alter the nature of an association (at least, in
structural terms) which was established by a superclass.  If we were
tempted to do so, then I think we'd have to question the quality of
our analysis model (e.g., "does this association really apply to this
whole superclass?").

I'd say in general that each association, at least in terms of
structure, *would* be completely orthogonal to other parts of the
abstraction of a class, including the other associations and
value-oriented attributes.  If so, then it's perfectly natural to deal
with each association one at a time, whether you do so in child units
or separate association packages.

>    If any extension to the current draft standard is required in this
>area--and I don't think one is--

Nor do I, really. (Even despite my post on "package abstracts" -- that
was more of a thought experiment, not a serious recommendation or
proposal.)  My belief is that Ada9X is quite expressive enough, all we
need to do is find creative combinations of the facilities that are
already there.

>it would be to change 3.2.3(6) to make
>child units eligible as primitive operations, probably under the
>influence of a pragma.   I certainly don't recommend such a change to
>the standard--it would open up all sorts of holes--but that should
>prevent someone from experimenting with such a pragma.

Certainly would be an interesting experiment, but dangerous. (Wear
protective gear. ;-) The difficulty I see is that the primitive
interface of a tagged type (embodied in its tag, perhaps implemented
as a method jump table) would be a fluid thing, dependant on how many
child units were actually compiled and "withed" within a program.  It
seems that a compiler alone would not be able to resolve this, and
that it would have to be a function of a linker.

>--

>					Robert I. Eachus

>with Standard_Disclaimer;
>use  Standard_Disclaimer;
>function Message (Text: in Clever_Ideas) return Better_Ideas is...


-- John Volan

--------------------------------------------------------------------------------
--  Me : Person := (Name                => "John Volan",
--                  Company             => "Raytheon Missile Systems Division",
--                  E_Mail_Address      => "jgv@swl.msd.ray.com",
--                  Affiliation         => "Enthusiastic member of Team Ada!",
--                  Humorous_Disclaimer => "These opinions are undefined " &
--                                         "by my employer and therefore " &
--                                         "any use of them would be "     &
--                                         "totally erroneous.");
--------------------------------------------------------------------------------




  parent reply	other threads:[~1994-10-04 16:00 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
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 [this message]
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