comp.lang.ada
 help / color / mirror / Atom feed
From: jgv@swl.msd.ray.com (John Volan)
Subject: Re: SOLVED! Decoupled Mutual Recursion Challenger
Date: Thu, 27 Oct 1994 02:15:41 GMT
Date: 1994-10-27T02:15:41+00:00	[thread overview]
Message-ID: <1994Oct27.021541.1696@swlvx2.msd.ray.com> (raw)
In-Reply-To: 1994Oct26.134825.1@rapnet.sanders.lockheed.com

gamache@rapnet.sanders.lockheed.com writes:

[Objections to the use of the term "Decoupled" in this thread.]

I fully agree, my use of the term "decoupled" was unfortunate.  In a binary
association, the two classes are indeed coupled, one way or another, and
I really wasn't trying suggest that we can eliminate that coupling.

On better reflection, I think I should have used a term more like
"Separately-Encapsulated Mutual Recursion".  The challenge I was 
proposing was how one could achieve the coupling necessary for
a mutually-recursive association while still being able to encapsulate
each class in its own separate package.  

Some folks have insisted that the "cleanest" way to achieve the
necessary coupling is to give up on separate encapsulation; both types
"must" be encapsulated in the same package.  The problem I saw with
this was that the effect would be transitive: Every time some other
class had to be associated, it would wind up being dumped into the
same package.  In the extreme case, *all* the classes in a large
semantic network would wind up inside of one, huge, monolithic
package.  This, I think, would defeat the whole purpose of packages
as a way of modularizing software designs.

"Gamache" (I'm sorry, you didn't sign your post, so I don't know your
full name) points out that there are various degrees of coupling, and
that, in particular, "content" coupling is the worst:

>In software engineering, it has become widely accepted that low coupling (such
>as data coupling) is good, whereas high coupling (such as content coupling) is
>bad.  If "decoupled mutual recursion" is moving on this scale, from where to
>where?  I couldn't make this out from the proposed solution.  In fact, this
>reasoning solidifies my initial opposition to it.  To see why, let me review the
>definition of one of the types of coupling listed above.  This definition is
>from Page-Jones, but similar definitions are available from a variety of
>authors, sometimes the name of the specific type of coupling is different, but
>the end result is almost the same.

>	Two modules exhibit content (or pathological) coupling if
>	one refers to the inside of the other in any way; for
>	instance,... if one module refers to (or changes) data
>	within another.... Such coupling makes nonsense of the
>	concept of black-box modules....

>Now I'm not saying that the above was the *intent* of the proposed solution;

Ironically enough, I think my original intent was to find a way to
*avoid* "content coupling."  If we're forced to declare two types
within the same package simply because they're associated to each
other, then the operations for either of the types would be able to
directly access the internal structure of the other type.  With
respect to each other, the two types would cease to be "black boxes".
No, I would rather see the two types encapsulated as private types in
separate packages, with no *direct* access to each other's structures.

>however, if I evaluate the type of coupling that the proposed solution
>*implements* (on the basis of xyz_Identity.Value being System.Address *and* the
>very existance of To_Pointer operation), I am forced to conclude that many
>modules *MAY* modify the data of one another ==> content coupling.

No, no! You're misinterpreting what my generic solution is doing! Each
"Xyz_Identity.Value" type is only going to be allowed *one* Pointer type
that it can be translated into.  I agree, if "Xyz_Identity.Translation"
could be instantiated more than once, then we'd break type safety and
general insanity would ensue.  But note that each Xyz_Identity package
has a guard that causes Program_Error to be raised if its Translation
sub-package is instantiated more than once.  Properly speaking, only
the package that actually implements the "Xyz" class should do an
instantiation of "Xyz_Identity.Translation", and only for its "Xyz.Pointer"
type.

Don't be confused by the use of System.Address as one of the possible
*implementations* of Identity.Value.  There are many reasons why
System.Address is a poor choice, but they have more to do with
portability, not type safety.  In fact, it's precisely because
Identity.Value *is* a "black box" that System.Address could be even a
half-way reasonable implementation for it.  There are better ways to
implement Identity.Value, but regardless of how it's done, it is still
going to be a "black box."  Remember, only valid Xyz.Pointers can go into
an Xyz_Identity.Value, and only valid Xyz.Pointers can come out.

I think the best way to understand what my Identity package does is to
focus on the term I used when I first introduced this solution:
"Deferred Coupling".  The Identity package makes it possible for the
inevitable coupling between two mutually-recursive classes to be
*deferred*, so that we can get on with establishing their interfaces
(package specs).  This is achieved by allowing an Xyz_Identity.Value
type to act as an "opaque forward declaration" for some Xyz.Pointer
type -- if you will, a "surrogate" that can stand in the place of that
Xyz.Pointer type, even at a point in time before it's possible to
declare the Xyz.Pointer type.  Eventually, we will establish the
coupling between Xyz_Identity.Value and Xyz.Pointer (by instantiating
Xyz_Identity.Translation), but, at least for a while, that coupling
can be *deferred.*

Also, don't be confused by the fact that two classes like Employee and
Office would contain pointers to each other (whether those pointers
are hidden in opaque identity values or not).  Yes, these pointers
mean that the two classes are coupled -- that's inevitable, and it's
the whole point to mutual recursion.  But it does *not* necessarily
mean that they are *content* coupled. If the pointer's designated type
(e.g.  Xyz.Object) is private, then there is no way that you can use
that pointer to *directly* manipulate the structure of the designated
object.  As you would expect, you have to go through the public
subprograms from the package spec where that designated private type
was originally declared.


>A Solution
>----------

["Gamache" goes on to suggest off-loading responsibility for the
association to another class of object that would represent the
association itself.]

Yes, several people have already suggested this solution.  I have
absolutely no trouble with this kind of scheme, and I fully accept the
fact that it is quite appropriate for some applications.  However,
that scheme is based on the premise that the associated classes do not
need to "know" about the association -- i.e., they do not need to 
bear any direct responsibility for the association.  Well, as long
as that premise holds, then it's okay.

Having said that, I still insist that there may be some applications,
or perhaps some styles of design, where it is not appropriate to make
that assumption.  Throughout this thread, I have taken it as a premise
that the two classes in an association would know about their
association and would share responsibility for it.  Essentially, I've
been asking the participants in this newsgroup to simply accept that
as an assumption for the sake of argument, and to see where that
assumption would lead.  Some people have vehemently refuse to do so,
even for the sake of argument.  Well, I can't force people to explore
ideas that they don't want to explore.  Nevertheless, I will be the
first to thank those folks for opening up my own mind to other
possibilities, even if those alternatives are based on different
assumptions.

["Gamache" also points out that Entity/Relationship analysis (such
as that of Shlaer/Mellor) may discover data attributes that pertain
not to either of the classes in an association, but actually to the
association itself.  This even more strongly suggests that the
association should be a class of objects itself.]

I wholeheartedly agree with this, but I don't think it changes the
nature of the problem.  Indeed, I think any such situation simply
brings up the same issues.  If, during analysis, a proposed
"association" becomes a class of object instead, then it is
conceivable that this new object class could end up in
mutually-recursive relationships with the two other classes.

Let me illustrate with an example:  Suppose you were considering
this association:

  +-------+                                            +-------+
  |       |     Is_Now_Or_Has_Ever_Beem_Married_To     |       |
  |  MAN  |(0..many)--------------------------(0..many)| WOMAN |
  |       |                                            |       |
  +-------+                                            +-------+

If we were to implement a mutually-recursive design to meet this
analysis, all we would have to do would be to endow the Man class
with a set of pointers to Woman objects, and vice versa.  However,
on further consideration, we might revise our analysis to allow
the association itself to have attributes, by making it a class
of its own:

  +-------+               +------------+               +-------+
  |       |               |            |               |       |
  |  MAN  |------(0..many)|  MARRIAGE  |(0..many)------| WOMAN |
  |       |               +------------+               |       |
  +-------+               | Start:Date |               +-------+
                          | End:Date   |
                          | ... etc... |
                          +------------+

Each Marriage object represents the particular association of one Man
and one Woman for some given period of time.  But now we effectively
have two associations between three classes of object.  My mutual
recursion question can still apply to this, as long as you accept my
basic premise.  We could distribute the responsibility for the
associations Man--has partaken of--Marriage and Woman--has partaken
of--Marriage to the classes involved.  Each Marriage object could hold
a pointer to a Man object and a Woman object, but each Man object and
each Woman object also could hold a set of pointers to Marriages.


>Summary
>-------

>(Maybe I should have put this at the beginning?) Anyway, I felt:

>o the proposed approach is an attempt to package content-coupling as a
>  feature rather than a liability.

Not true.  Indeed, the exact opposite is true, as I have argued.

>o the problem statement is not new or rare, nor does it have much to do
>  with subclasses, rather it is a problem concerning associative objects.

I fully agree, as long as you allow the possibility of substituting the
phrase "associations between objects" for the phrase "associative objects."
I concur that there should not be any need to resort to abstract classes
and inheritance just to achieve "separate encapsulation".

>o existing techniques are available and in place for dealing with
>  associative object implementations in a low-coupled fashion.

Fully agree -- but this is only one possible style of design.  Your
experience may have encouraged you that this is the best style for the
kind of applications you have tackled, but please do not assume that
it's perfect for all applications.  As evidence, please consider the
fact that "Separately Encapsulated Mutual Recursion" is effectively
supported by other languages, including C++ and Eiffel.  I think it
would be a good idea if Ada9X could support it as well, in some
reasonable way.

>While its certainly possible I've been misreading this thread, to get 
>realigned I would need identification of what type of coupling one is 
>"decoupling" and what type one is ending up with.

If anything, I think my challenge (and my solution to it) attempted to
promote the best possible form of coupling ("data" coupling?) and to
discourage the worst form, by preserving the separate encapsulation
of classes.

--------------------------------------------------------------------------------
--  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.");
--------------------------------------------------------------------------------




  reply	other threads:[~1994-10-27  2:15 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1994-10-12 22:49 SOLVED! Decoupled Mutual Recursion Challenger John Volan
1994-10-17 15:48 ` John Volan
1994-10-17 17:55   ` Bob Duff
1994-10-17 20:52     ` John Volan
1994-10-17 22:10       ` Bob Duff
1994-10-18 22:17         ` John Volan
1994-10-19  1:01           ` Bob Duff
1994-10-19  4:45             ` Jay Martin
1994-10-19 14:38               ` Mark A Biggar
     [not found]                 ` <38fi4r$l81@oahu.cs.ucla.edu>
1994-10-24 11:49                   ` Mutual Recursion Challenge Robert I. Eachus
1994-10-24 20:32                     ` John Volan
1994-10-26 11:42                       ` Generic association example (was Re: Mutual Recursion Challenge) Robert I. Eachus
1994-10-26 23:21                         ` John Volan
1994-10-27 10:53                           ` Robert I. Eachus
1994-10-31 17:34                             ` John Volan
1994-10-27 14:37                           ` Mark A Biggar
1994-10-24 17:42                   ` SOLVED! Decoupled Mutual Recursion Challenger John Volan
1994-10-24 22:37                     ` Jay Martin
1994-10-25  5:47                       ` Matt Kennel
1994-10-25 10:04                         ` David Emery
1994-10-25 16:43                         ` John Volan
1994-10-27  4:25                           ` Rob Heyes
1994-10-28  9:03                             ` Mutual Recursion (was Re: SOLVED! Decoupled Mutual Recursion Challenger) Robert I. Eachus
1994-10-28 15:04                             ` SOLVED! Decoupled Mutual Recursion Challenger Robb Nebbe
1994-10-25 15:54                       ` John Volan
1994-10-26  1:24                         ` Bob Duff
1994-10-28  4:28                         ` Jay Martin
1994-10-28 10:52                           ` Robert I. Eachus
1994-10-28 18:46                             ` Jay Martin
1994-11-02 14:56                               ` Robert I. Eachus
1994-10-29  0:38                           ` Bob Duff
1994-10-29  7:26                             ` Jay Martin
1994-10-29 11:59                             ` Richard Kenner
1994-10-31 13:17                               ` Robert Dewar
1994-10-31 14:13                               ` gcc distribution (was: SOLVED! Decoupled Mutual Recursion Challenger) Norman H. Cohen
1994-11-02 14:14                                 ` Richard Kenner
1994-11-04 23:56                                   ` Michael Feldman
1994-10-31 18:44                           ` SOLVED! Decoupled Mutual Recursion Challenger John Volan
1994-10-20 11:25               ` Robb Nebbe
1994-10-20 19:19                 ` John Volan
1994-10-26  0:07                 ` Mark S. Hathaway
1994-10-26 18:48                 ` gamache
1994-10-27  2:15                   ` John Volan [this message]
     [not found]           ` <CxwGJF.FwB@ois.com>
1994-10-19 16:35             ` John Volan
1994-10-17 22:54   ` Cyrille Comar
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox