comp.lang.ada
 help / color / mirror / Atom feed
From: mmann@ibm.net (Gerd Moellmann)
Subject: Re: OO Idiom: Interfaces for derived classes
Date: 1996/03/22
Date: 1996-03-22T00:00:00+00:00	[thread overview]
Message-ID: <mmannvijxa4ta.fsf@ibm.net> (raw)
In-Reply-To: 4is6mk$1dn6@watnews1.watson.ibm.com

ncohen@watson.ibm.com (Norman H. Cohen) writes:

> |> After studying the ARM and "Ada as a second language" (Normal
>                                                                ^
> This is an abnorman way to spell my name, but that's okay.  I've been
> called worse things than "normal". ;-)

:-))

> Note that your solution still requires voluntary compliance with a
> convention--that only units implementing derived classes should contain
> with clauses for base_package.derived.

Yes, the proposal requires voluntary compliance (which can be easily
checked if necessary) and it requires programmers to take an explicit
action---with'ing base_package.derived---to gain access to base class
internals. 

> Rather than trusting the whole rest of the program, I prefer the
> "traditional" solution of declaring descendents of base_class in child
> packages of base_package, which is more straightforward and only requires
> trusting the writers of those child packages to use declarations in the
> private part of base_package appropriately.

If we talk about "trusting" (I am not concerned about programmers
cluttering up something intentionally; I am primarily aiming at
getting a less coupled implementation with my proposal):

Don't class libraries, frameworks/patterns often require users to
derive classes from library classes?  Can it always be foreseen from
which classes it might be desirable to derive new classes?  The
"trusting scheme" would have to trust quite a lot of people, IMO.

> (If you are not the trusting sort, you can use an access-management
> tool to ensure that no "unauthorized" children of base_package are
> written.  After all, you must trust programmers not to make unauthorized
> changes to the text of base_package itself, or else enforce this with an
> access-management tool.  Page 471 of _Ada_as_a_Second_Language_ states,
> "In a sense, since a child unit is logically nested inside its parent,
> the author of a child package creates a modified version of the parent
> package.  Only a programmer who would be trusted to modify the text of
> the parent itself should be trusted to write a child unit of a package
> with a private part.")

I agree that this is true when derived classes are implemented in
child packages.  But I must add that it sounds like placing a burden
on programmers to me. I think of an application programmer using, say,
one class library for the user interface, another for database access,
and yet another one for communications.  If I had the choice to
either protect her against inadvertantly relying on non-public
features of one of maybe several hundred classes or trust her, I would
prefer the first alternative.

> The situation gets more complicated when we turn our attention from a
> snapshot, or release, of a program to a program as an living entity that
> evolves over time, or to the distribution as a reusable component of a
> package providing some OO class.  Then it becomes important for the
> writer of the parent package to provide documentation distinguishing
> those aspects of the parent package that represent supported parts of its
> interface from those parts of the parent package that represent
> implementation choices that may change in future releases of the parent
> package.  At one extreme, the writer of the parent might guarantee the
> proper functioning of the package only as long as no children are written
> for it.  At the opposite extreme, the writer of the parent may commit to
> preserving all the declarations in the private part of the package in all
> future releases.  But the child should ask not (just) what the parent can
> do for it; the child should ask too what it can do for (or to) its
> parent:  If the writer of the parent does not rule out child packages
> entirely, he must also document those invariants that all children of the
> package must preserve if the package is to continue to function
> correctly.

Agreed. This is true no matter how you implement derived classes.

> Back to the idiom you propose:  The usual reason for a derived class
> referring directly to members of a base class is efficiency. 

You can gain efficiency in my scheme by inlining subprograms.

> If you are
> going to force all manipulations of the base-class implementation to be
> through subprograms exported by Base_Package.Derived anyway, you lose the
> motivation for giving implementations of derived classes special
> privileges. Why distinguish then between operations that are acceptable
> only for derived classes to perform and those that are acceptable for all
> clients to perform?  If you have truly hidden the implementation of the
> base class from derived classes, then it would seem that any operation
> deemed safe for the implementation of the derived class to perform will
> also be safe enough for the world at large to perform.  If you have a
> specific example that suggests otherwise, it would be interesting to
> see it.

To cite [Rumbaugh, Object Oriented Modeling & Design, 1991 (p.322)],
(hope I got the name right:-), and this the intention behind my proposal:

"Encapsulation can be violated through careless use of inheritance. A
subclass inherits the attributes of its superclass, but if the methods
of the subclass directly access superclass attributes, the
encapsulation of the superclass is defeated.  CLOS, Owl, Eiffel and
C++ permit a class to restrict the visibility from its subclasses.
There are arguments in favor of allowing a class to access its
superclass, but the cost is tight binding between the classes.

Often it is useful to write some "private" operations that are for
internal use only by other methods of the same class. It is desirable
to restrict the visibility of these operations so that other classes
cannot use them.  It is often necessary to allow subclasses to access
these internal operations, so a simple distinction between public and
private is not possible..."

This meets exactly my experience in early C++ projects. Classes end up
tightly coupled.  Modifications/extensions become harder and harder
over time.  I believe this lesson was learned in C++---I didn't see
many C++ class libraries (maybe none?) in the last years.

> Having said all that, if you really want to, there IS a way in Ada 95 to
> mimic the C++ distinction between protected and private members, at the
> cost of a level of indirection when accessing private members: 
> 
>    package P is
>       type T is tagged private;
>       ...
>    private
>       type Private_Components_Type;
>       type Private_Components_Pointer_Type is access Private_Components_Type;
>       type T is tagged
>          record
>             ...  -- "protected" components declared here
>             Private_Components : Private_Components_Pointer_Type;
>          end record;
>    end P;
> 
>    package body P is
>       type Private_Components_Type is
>          record
>             ... -- "private" components declared here
>          end record;
>       ...
>    end P;
> 
> The "protected" components are visible in the private parts and bodies of
> children of P, but the "private" components are not.
> 

Yes, this letter-envelope pattern is usefull in its own right. As you
said, its costs can be high because the base class itself can only
access the private part with an additional indirection.

Thank you for your answer, Norman.  Although it didn't convince me to
drop my proposal it was interesting to hear your opinions.  May I add
a congratulation for your really fine book "Ada as a 2nd language"?
-- 
Gerd Moellmann, Altenbergstr. 6, D-40235 Duesseldorf, Germany
Software Development & Consulting
Internet: mmann@ibm.net / CIS: 100025,3303 / Phone: +49 211 666 881




  reply	other threads:[~1996-03-22  0:00 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1996-03-21  0:00 OO Idiom: Interfaces for derived classes Gerd Moellmann
1996-03-21  0:00 ` Norman H. Cohen
1996-03-22  0:00   ` Gerd Moellmann [this message]
1996-03-22  0:00     ` Norman H. Cohen
  -- strict thread matches above, loose matches on Subject: below --
1996-03-22  0:00 Jean-Pierre Rosen
1996-03-22  0:00 ` Gerd Moellmann
1996-03-22  0:00 ` Norman H. Cohen
replies disabled

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