comp.lang.ada
 help / color / mirror / Atom feed
From: eachus@spectre.mitre.org (Robert I. Eachus)
Subject: Re: Generic association example (was Re: Mutual Recursion Challenge)
Date: 27 Oct 94 10:53:37
Date: 1994-10-27T10:53:37+00:00	[thread overview]
Message-ID: <EACHUS.94Oct27105337@spectre.mitre.org> (raw)
In-Reply-To: jgv@swl.msd.ray.com's message of Wed, 26 Oct 1994 23:21:54 GMT


    (I'll post one last time on this subject here, then take any
follow-up to mail.)

In article <1994Oct26.232154.29094@swlvx2.msd.ray.com> jgv@swl.msd.ray.com (John Volan) writes:

  > I suppose we could apply a pragma Suppress at some point to
  > eliminate the extra dynamic check, once the program was fully
  > tested.  But, more to the point, we've lost a certain amount of
  > expressibility.  Since the Ada code doesn't directly express what
  > we mean, its readability by other Ada programmers (for example,
  > maintainers) is reduced.

   Let the compiler do the work.  If there is only one concrete type
in an abstract class, the check might result in a call at run-time to
a check, but the check should be implemented as a return instruction.
If there are types derived from Office or Person, there may be an
actual check in some other cases that you want made.  But any compiler
that does run time checks for abstract types, or builds dispatch
tables for abstract types has a bug.  (There are cases where you may
have a view of an object as an abstract type, but that must always be
a static view--at least, that is the intent.)

  > What cannot be easily named, cannot be easily explained, and
  > therefore cannot be easily understood.

    The style of Ada 9X programming I am focusing on addresses this by
making that disappear from sight.  The only objects visible in the
"main" program should be complete objects of complete types.  The rest
should be treated like making sausage or scrapple and hidden in
private parts whereever possible.

  > But that's not the only way you could arrange things.  If you
  > noticed, in my previous posts, I actually conceived of
  > *distributing* this "Setting" responsibility to *both* of the
  > classes.  In other words, I imagined having *two* "Associate"
  > operations: one that was primitive for an Employee and one that
  > was primitive for an Office.  The Associate for Employee would
  > only directly modify the Employee's pointer to its Office;
  > likewise the Associate for Office would only directly modify the
  > Office's pointer to its Employee.  That follows the "Law of
  > Demeter": an object's operations should only directly manipulate
  > its own attributes, but not the attributes of any other object.

  > However, both of these Associate operations would also be
  > responsible for satisfying the invariant of the association: i.e,
  > if an Employee points to an Office, then that Office must point
  > back to that Employee as well.  The most convenient way for the
  > two Associate operations to do that would be ...  to call each
  > other!  In other words, they would be *mutually recursive*
  > subprograms, reflecting the *mutually recursive* relationship
  > between the two classes.

      Excellent reasoning, but I wouldn't code the blasted bodies that
way.  Infinite recursion is frowned upon, so if set for office calls
set for person and vice-versa, something has to break the loop.  The
"best" way I found was to set the local attribute, then check the
remote attribute and if it was "wrong" call the matching set.  It
works, but it is pretty kludgy.  I'm willing to pay a bit for
elegance, but that's a little expensive.  Above you talk about
eliminating redundant checks, here you not only prohibit simple
operations from being effectively inlined, but require a check that
the thing you just set has the right value.

      According to ME ;-) the association package "owns" the Attribute
fields and is the only one to monkey with them, and this is the right
and proper approach in Ada 9X.  It is different, but it seems better
from an encapsulation point of view.  With the Smalltalk or C++ model
large and complex object implementations soon get buried in
interactions between different components of an object.  In this
model, each abstraction takes care of its own.

      I left some stuff out here for simplicity, but in a "real"
implementation of this idea, I would insist that both object be
derived from Controlled, or Limited Controlled, and I would insure
that there were no dangling pointers when an object was destroyed, and
that copying an object did not copy the assignments. (In a many-to-one
or many-to-many implementation the policy would be different of
course.)  In other words, fix all those bugs before they occur, and
transparent to the user of the abstraction.

  > You see, that's what I mean -- you've lost the ability to express
  > the exact type of the other object in a static fashion, even
  > though you, as the designer, do know what that exact class should
  > be, a priori.

   In the instance you can use subtypes and renames to express things
right, and in a real world application, as I said I would put as much
of this as possible in the private part.  (Due to the form of the
generic, the outer instance must be public, but that's about it--other
than the operations and types you want to show.)

  > Interesting interpretation.  I didn't think there was any trouble
  > with returning "null".  Clients could just interpret a "null"
  > value as meaning that E isn't associated with any Target.  But
  > that's okay -- you just have a slightly different abstraction in
  > mind than I have.

   Major difference, but subtle in its way.  I hid the "pointer"
types, so all external interfaces deal with objects, not pointers to
objects.  Yes, we know that what gets passed around is a reference,
so there is no extra calling overhead, but doing it this way
eliminates--if done correctly--dangling pointer worries for users of
the abstractions.  I didn't show all of that, but for example, the
finalization operation on a Person would unset his office.  So there
is no null value to return.

  > >       procedure UnSet(E: in out Extended'CLASS);
  > >        procedure UnSet(IE: in out Extended'CLASS);
  > >       -- UnSet the attribute.  If already set, unset the partner as well.

  > By the way, in the case of "many"-cardinality, I think UnSet would
  > actually wind up being a single operation with two parameters.

   (Read a little closer.  UnSet can always get the partner when
needed, and the code does it that way.  But, yes, you also need the
two parameter form in the many-to-many mapping to remove exactly one
pairing.)
--

					Robert I. Eachus

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



  reply	other threads:[~1994-10-27 10:53 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 [this message]
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
     [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