comp.lang.ada
 help / color / mirror / Atom feed
* OO vs Reality:  An Ada 95 Solution?
@ 1996-12-14  0:00 Marc A. Criley
  1996-12-14  0:00 ` Matthew Heaney
  0 siblings, 1 reply; 2+ messages in thread
From: Marc A. Criley @ 1996-12-14  0:00 UTC (permalink / raw)



OO vs Reality:  An Ada 95 solution?

A dilemma often occurs when implementing an OO solution to a particular
implementation problem.  Given a well-defined, cohesive class, the
preferred Ada implementation is to implement the class within a single
package.  The class attributes are defined as private, limited, private, or
hidden in the body, as appropriate.  The operations (or services or methods
or whatever) are defined in the package spec to permit manipulation of
class objects.

The problem arises when some small bit of information about this class is
needed by another, such as the values a particular attribute may hold.  The
entire class in which those values are defined gets dragged along with that
type definition.  One might argue that smart compilers/linkers/code
strippers can remove the unnecessary code, but I feel that misses the
point.  Why should all the operations be brought in when all that's needed
is (for instance) an index range?

The needed attribute type definition could be pulled out of the class and
placed in a (gasp!) common types package, but where does that end?
Eventually most of the types get migrated to such packages, with only
attribute declarations and operations remaining in the now not-so-cohesive
class package.

Utilizing Ada 95's child packages could provide a compromise solution (or
bastardization, depending on how you look at it. :-)  The following is
submitted for discussion:

A package is created to contain the class' attributes (if appropriate),
accessors, constructors, destructors, and _very_ primitive operations,
i.e., the class is effectively useless without them.  A child package is
then created to supply the specifications for the class operations.  This
permits those other classes that need only access to attributes or their
type definitions to simply "with" the parent package, while those classes
that do more extensive manipulation can "with" the child package.
Cohesiveness is maintained, albeit in a parent-child package relationship,
which Ada 95's semantics bind far more closely than with the usual types
package/procedures package relationship.

This seems to me to be a good compromise, that is, I'm not totally ga-ga
over it, but it does seem to resolve the dilemma rather effectively.  I'm
interested in comments, criticisms, and earlier references to this
technique.

One last note: To be able to migrate to this technique when one is
currently using Ada 83, the appropriate implementation is to collect all
attributes and operations into a single package and just live with the
excess for now.  When the time to migrate to Ada 95 arrives, it becomes a
mostly mechanical process to split the class package into parent and child,
and then change references to the operations to reflect their new location
in the child package.

Marc A. Criley
Software Practitioner

OOA = (Re)packaging, OOA /= Decomposition





^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: OO vs Reality:  An Ada 95 Solution?
  1996-12-14  0:00 OO vs Reality: An Ada 95 Solution? Marc A. Criley
@ 1996-12-14  0:00 ` Matthew Heaney
  0 siblings, 0 replies; 2+ messages in thread
From: Matthew Heaney @ 1996-12-14  0:00 UTC (permalink / raw)



In article <58ue6j$b4l@nw101.infi.net>, mcriley@bix.com (Marc A. Criley) wrote:

>The problem arises when some small bit of information about this class is
>needed by another, such as the values a particular attribute may hold.  The
>entire class in which those values are defined gets dragged along with that
>type definition.  One might argue that smart compilers/linkers/code
>strippers can remove the unnecessary code, but I feel that misses the
>point.  Why should all the operations be brought in when all that's needed
>is (for instance) an index range?
>
>The needed attribute type definition could be pulled out of the class and
>placed in a (gasp!) common types package, but where does that end?
>Eventually most of the types get migrated to such packages, with only
>attribute declarations and operations remaining in the now not-so-cohesive
>class package.

There's nothing wrong with common types packages, as long as you do it
correctly.  Most shops get it wrong by putting every type in the system in
a  Common_Types package, and the result is a compilation nightmare.

Like any system, you must minimize the dependencies among the subsystems. 
In an Ada program, this is the same as saying you must minimize the
compilation dependencies among the modules.

The key is that a types package should have a collection of "cohesive"
types, ie they are strongly related to each other.  Common types packages
are OK, just have a few of them (not just 1, that would be huge mistake)
with each having a few highly cohesive types.

I'll define what it means to be cohesive below.

The solution for you is to have a common types package that contains the
single type you need, and this types package gets with'd by the 2 packages
that need it (and those are the only 2 that with it).  For example,

package ADT_Types is

   type Index_Range is 1 .. 10;  -- say

end;  

Here's client number 1:

with ADT_Types;
package ADT_Package is

   type T is tagged private;

   procedure P (O : T);
...
private 
   
   type A is array (ADT_Types.Index_Range) of ...;
   type T is
      record
         O : A;
         ...
      end record;

end ADT_Package;

And here's client number 2:

with ADT_Types;
package Some_Other_Package is

   ... -- uses type ADT_Types.Index_Range somehow
end;

Time and time again I see shops that have, say, 1 common types package,
shared by all the modules in the system.  Big, big mistake.  Have a few
common types packages (where necessary), each one shared by only a few of
the modules in the system.

A good example of a cohesive module is the standard Ada 95 package
Interfaces.  It contains declarations of interface types (such as
Unsigned_16, etc) and nothing else.

Of course, there's nothing wrong with just putting the type in the
ADT_Package, and having the client with that package to get at the type. 
If you don't use any other resources exported from that package (and if
you're using an incremental compiler) then you shouldn't be affected by any
changes.

You do bring up an interesting point, though, which relates to module
design.   Thinking about how to properly organize the modules (packages) is
every bit as important as the class design in an (object-oriented) system. 
Most of the books out there nowadays discuss class design, but give module
design short shrift.  So it's no real surprise that many Ada programmers
get it wrong.

I have a friend who favors C.  His comment about us was that "You can
always tell who the Ada programmers are - they're the ones reading a
newspaper at their terminal."  He was refering to the fact that many Ada
programmers often have to wait a long, long time for the compile to finish.

But there's no need for that!  The problem is that most Ada programmers
don't understand module design, and aren't aware of the techniques to
minimize module coupling.  (Actually, most programmers don't even know what
"coupling" and "cohesion" are.)

Something Booch recognized early on was that to implement an abstraction
often requires more than a just a single class or package.  My own
experiance confirms this.

There'll be a small group of Ada packages that are "highly cohesive,"
working together to implement an abstraction.  Spreading the work out this
way prevents you from having a single but huge package to do the work.

The designers of Ada 95 recognized this idiom and added language support
for a "subsystem," defined as a collection of child library units that
share a common library unit root.  For the implementation of a complex
abstraction, typically one package serves as the interface to the rest of
the world, and the other (private) packages serve as the "body" of the
abstraction.

This group of packages that implement a complex abstraction typically share
some common types.  So just put the types in a "common types" package that
gets with'd by - and only by - the packages in the subsystem.

That's the answer to your question "Where does putting types in a common
types package stop?"  The type you're interested in gets put in the types
package for *this* subsystem. And other subsytems can have their own
common-to-the-subsystem types package.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
mheaney@ni.net
(818) 985-1271




^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~1996-12-14  0:00 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1996-12-14  0:00 OO vs Reality: An Ada 95 Solution? Marc A. Criley
1996-12-14  0:00 ` Matthew Heaney

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