comp.lang.ada
 help / color / mirror / Atom feed
From: "John G. Volan" <johnvolan@sprintmail.com>
Subject: Re: circular unit dependency
Date: 1997/06/05
Date: 1997-06-05T00:00:00+00:00	[thread overview]
Message-ID: <33970BAF.3F61@sprintmail.com> (raw)
In-Reply-To: mheaney-ya023680000506970129100001@news.ni.net


Matthew Heaney wrote:
> 
> In article <3393D0E1.AC9@sprintmail.com>, johnvolan@sprintmail.com wrote:
> 
> >Perhaps you just haven't worked on the kinds of problems where this
> >issue arises.  There are a lot of ways to skirt the issue (see section 3
> >of my FAQ for a few).  But there are just some domains where this
> >pattern is the most straightforward one, the one that preserves the most
> >abstractions.
> 
> Perhaps that's true.  Bob Eachus and those guys gave examples the last time
> we...um..."discussed" this ...um.. "issue" in the language, where recursive
> packages neatly solved the problem.

What is a "recursive" package? Do you mean a package encapsulating two
types that are mutually dependent?  Yes, that is a legitimate coding
pattern too, but I disagree that it is always appropriate for every case
of mutually-dependent types (i.e., types whose primitive operations
include parameters of the other type).  I even disagree that it is
always appropriate for mutually _recursive_ types (types whose
structures must contain references (e.g. access values) designating the
other type).  I think the key question is whether the types need access
to each other's implementation details or just each other's interfaces.

With regard to the past discussion of this topic: Although it became
heated at times, I believe it always remained civil.  I did make a point
of criticizing all those conservative voices that kept denying there was
a problem. I will continue to challenge anyone who continues to deny the
problem.  But I viewed it then, and I view it still, as an intellectual
debate, not a personal or political one.  This is why I chafed at those
who tried to make it personal or political.

I especially chafed at those who dogmatically repeated the litany: "Do
it our way, or go program in something else."  I stubbornly refused to
do that, and instead proposed an Ada0Y solution (thus goading Norman
Cohen and Tucker Taft to propose other comparable solutions), and kept
pushing until I found a workaround that can be used today (and is). Now,
who do you think has gone further to promote Ada, me or the dogmatics?

> Right now I'm doing a job for a client who insisted that each ADT get its
> own package (even if it were a nested one), even when colocating the types
> would have been the most natural solution.  The result is a bloody mess.

This is why I have been trying to promote "1 package = 1 type" as a
design pattern _among_ design patterns.  Neither this pattern, nor the
co-encapsulation pattern, should be viewed as the "One True Way".  Each
has _appropriate_ applications.  Those who are dogmatic for one or the
other, without weighing the design tradeoffs, are just displaying poor
engineering judgment.  And I for one am not afraid to call it that, when
I see it, no matter how highly esteemed the personage involved.

> The example is of a queue and its iterator.  Obviously the iterator has to
> know the representation of the queue, so it can iterate over it.  But the
> queue also keeps track of the iterators that have registered with it, so
> that it can adjust the pointer if an element is removed from the queue.

This is exactly the sort of case I had in mind where co-encapsulation
_can_ be justified: The types are very tightly coupled, and need to know
each other's _implementations_.  But this case should be carefully
distinguished from loosely coupled types that don't need to know each
other's implementation details, yet still collaborate with each other in
terms of each other's abstractions.

> Now, this is certainly not the smartest way to do iteration (they didn't
> need all that power, nor the attendent complexity), but the queue
> abstraction was made unnecessarily complex because it didn't have
> visibility to the representation of the iterator, which was in a nested
> package.  The simple solution would have been to just put the 2 types
> together in the same package, so they could see each other's
> representation.

Hmm. I think there might be a way for you to satisfy your employer while
at the same time simplifying your life a bit.  Your boss wants the
iterator type to be visible in its own package, fine. But who says it
actually has to be _implemented_ there?  Here's the idea:

(1) Move your iterator type to a child of your container package.

(2) Write an iterator implementation type inside your container package,
but hide it in the private part.  The container type and the iterator
implementation type can know each other's implementation details.

(3) Privately implement your iterator type in the child package using
the ready-made iterator implementation type from the parent container
package.  

  package Containers is
    type Container_Type is ... private;
    ... -- primitive Container operations
  private
    type Iterator_Implementation_Type is ...
    ... -- primitive Iterator_Implementation operations
    type Container_Type is ...
  end Containers;

  package Containers.Iterators is
    type Iterator_Type is ... private;
    ... -- primitive Iterator operations
  private
    type Iterator_Type is
      record
        Implementation : Iterator_Implementation_Type;
      end record;
  end Containers.Iterators;

In other words, Containers.Iterators is just a "skin" package providing
access to something already built-in (but hidden) in the Containers
package.  You'll have to implement the Iterator_Type operations using
delegation: Each Iterator_Type operation needs to explicitly call the
corresponding Iterator_Implementation_Type operation. (Inheritance won't
work, because you can't take privately-inherited features and make them
public.)  But this way, the real guts of the iterator implementation can
be in the same package with the container guts.

> This is the about the only degree of colocation I've ever seen necessary: 2
> types that are mutually dependent.  I'm not suggesting put "24 types"
> together in the same package, and agree completely that that would be a bit
> confusing!  (Though the reader of my examples posted on the SIGAda Patterns
> WG home page should be warned: my toy examples all feature multiple types
> per package!)
> 
> My real issue is with this coding convention that's been floating around
> for years, that says something like "Thou shalt put only one ADT per
> package."  If you blindly apply a rule like that, without any thought at
> all (like on my current project), then you're going to make your code very
> complex.  The guideline should be stated "Don't put unrelated types
> together in the same package," because that would increase coupling.  (It
> gives a client interested in only one of the types an unnecessary
> compilation dependency on the other.)
> 
> Glib application of the former rule is also a warning sign that the shop
> isn't really thinking in Ada, and is confusing module and type.  Natural
> and elegant solutions are only effected by immersing oneself in the
> language, and not fighting its idiosyncrasies.

Violent agreement. :-) Just beware that, in fighting one dogma, you
don't inadvertently promote another...

------------------------------------------------------------------------
Internet.Usenet.Put_Signature 
  (Name       => "John G. Volan",
   Employer   => "Texas Instruments Advanced C3I Systems, San Jose, CA",
   Work_Email => "johnv@ti.com",
   Home_Email => "johnvolan@sprintmail.com",
   Slogan     => "Ada95: World's *FIRST* International-Standard OOPL",
   Disclaimer => "My employer never defined these opinions, so using " & 
                 "them would be totally erroneous...or is that just "  &
                 "nondeterministic behavior now? :-) ");
------------------------------------------------------------------------




  reply	other threads:[~1997-06-05  0:00 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1997-05-24  0:00 circular unit dependency jdlopez
1997-05-24  0:00 ` Michael F Brenner
1997-05-25  0:00 ` Jon S Anthony
1997-05-26  0:00   ` John G. Volan
1997-05-26  0:00     ` Fergus Henderson
1997-05-27  0:00     ` Jon S Anthony
1997-06-02  0:00     ` Ada95=>Ada0Y Process? [was: circular unit dependency] John G. Volan
1997-06-04  0:00       ` Ada95 packages, C++ namespaces, & circular dependencies John G. Volan
1997-06-07  0:00       ` Ada95=>Ada0Y Process? [was: circular unit dependency] Robert Dewar
1997-06-07  0:00         ` John G. Volan
1997-06-08  0:00           ` Robert Dewar
1997-06-08  0:00             ` John G. Volan
1997-06-07  0:00         ` John G. Volan
1997-05-28  0:00 ` circular unit dependency John G. Volan
1997-06-01  0:00   ` John G. Volan
1997-05-31  0:00 ` Kevin Cline
1997-05-31  0:00   ` John G. Volan
1997-06-01  0:00     ` Kevin Cline
1997-06-01  0:00       ` John G. Volan
1997-06-02  0:00     ` John G. Volan
1997-05-31  0:00   ` Matthew Heaney
     [not found]     ` <33932F31.4399@sprintmail.com>
1997-06-02  0:00       ` Matthew Heaney
1997-06-03  0:00         ` W. Wesley Groleau (Wes)
1997-06-03  0:00           ` John G. Volan
1997-06-03  0:00         ` John G. Volan
1997-06-05  0:00           ` Matthew Heaney
1997-06-05  0:00             ` John G. Volan [this message]
1997-06-06  0:00             ` Stephen Schmid
  -- strict thread matches above, loose matches on Subject: below --
1998-05-26  0:00 Brendan Reville
2003-05-23  9:20 Mirko Aigner
2003-05-23 11:37 ` Jeffrey Creem
2003-05-23 12:12   ` David C. Hoos
2003-05-23 18:08 ` Stephen Leake
2003-05-24 22:12   ` Robert I. Eachus
2003-05-26  8:05   ` Mirko Aigner
2005-01-04 18:31 R
2005-01-04 23:45 ` Randy Brukardt
2005-01-05  8:35   ` Martin Krischik
2005-01-05  8:55     ` Duncan Sands
2005-01-05  0:26 ` Stephen Leake
replies disabled

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