Topic: Proposal: 'protected friend:


Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Sun, 26 Feb 1995 06:12:21 GMT
Raw View
In article <3i0atd$dca@hawk.csd.harris.com>,
Bill Leonard <Bill.Leonard@mail.csd.harris.com> wrote:
>
>I use protected and private to protect myself from my own and others'
>stupidity.

 Thats not really the main use though. The purpose of
protection is to enforce encapsulation, and the purpose of
encapsulation is to provide representation independence.

 So, enforcement or not, the main function of "private"
is to ANNOUNCE that part of the interface is not INTENDED for
public use. The fact that it is enforced in C++ is an added bonus:
comments serve the main purpose just as well in C (for example).

 What I'm saying is that the "Contracting Paradigm"
is what "private" and "public" serve first: they are
specifications that separate the type from its implementation
(when both use the same syntactic forms -- members).

 This lets you change the implementation AND/OR derive
classes that work. You don't make data private to STOP
anyone --even yourself-- accessing it, you make it private
to SPECIFY that it is not part of the type, but of its
implementation.


--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: az915@FreeNet.Carleton.CA (William G. Royds)
Date: Mon, 20 Feb 1995 21:51:20 GMT
Raw View
In a previous posting, Bill Leonard (bill@amber.ssd.csd.harris.com) writes:
 <proposal for allowing privacy control on friend functions and classes>.

  Friend functions are NOT equivalent to member functions because they exist
outside of the class that they are friends too. They are often used as
object of function pointers because of their static address. Because they
often are neccessary for a very restricted use, they should also be restricted
in their access to the class giving access. If one designs a system with
multiple co-operating but small classes, one wants to control access to each
individual class. The present semantics of friend makes this not a useful
design.

--
Bill Royds           az915@freenet.carleton.ca     C.L.B.R.R. Ag Canada
Ottawa, Ontario      ROYDSW@ncccot.agr.ca          Scientific Software Support




Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 15 Feb 1995 23:07:44 GMT
Raw View
In article 95Feb15150616@splinter.coe.neu.edu, jcox@splinter.coe.neu.edu (Jonathan J. Cox) writes:
>
>Proposal for New C++ Language Extension:    'protected friend'
>
>
>I'm very interested in hearing what people have to say about this.
>Please *post* your reply (my mailbox runneth over!).
>
>   - Thanks in advance
>----------------------------------------------------------------------
>
>
>While ordinary friendship ('private friendship') grants access to the
>protected and private sections of a class, 'protected friendship' would
>only grant access to the protected section:

There was a moderately long thread on exactly this idea a few weeks ago.

Properly viewed, a friend function is part of the public interface of
the class, and except for the syntax you use to call it is equivalent to
a public static member function.

If one proposes limiting access of friend functions, one would also have to
propose the same for all public member functions. No one ever proposes
that, however.

Personally, I don't see that this kind of fine-grained tweaking has any
benefit. For one thing, why do you want to restrict access of a (member)
function of your own class that you are writing? (Someone else might
write it, but it is conceptually you writing it by proxy.)

As a separate but related issue, many C++ experts now recommend against
using protected members at all. The reasons for making something private
are to hide implementation details that could be misused, and to allow a
change in implementation details without affecting code in other modules.

Making something public is a promise that the interface will be preserved.

Making something protected means that you don't want to expose it to
just anyone. Yet you cannot predict what classes will be derived from
your class, or by whom, or under what circumstances. (Notice the contrast
with friend functions: there are no friend functions except the ones
you declare and write.) This means you cannot change the protected interface
either. Further, you can no longer ensure that the protected interface will
not be misused by the author of a derived class who did not understand the
consistency requirements. You might as well make the thing public.

---
Steve Clamage, stephen.clamage@eng.sun.com






Author: bill@amber.ssd.csd.harris.com (Bill Leonard)
Date: 16 Feb 1995 20:00:45 GMT
Raw View
In article <3hu1g0$pea@engnews2.Eng.Sun.COM>, clamage@Eng.Sun.COM (Steve Clamage) writes:
> In article 95Feb15150616@splinter.coe.neu.edu, jcox@splinter.coe.neu.edu (Jonathan J. Cox) writes:
> >
> >Proposal for New C++ Language Extension:    'protected friend'
>
> There was a moderately long thread on exactly this idea a few weeks ago.
>
> Properly viewed, a friend function is part of the public interface of
> the class, and except for the syntax you use to call it is equivalent to
> a public static member function.

Properly viewed, any function is just software and can access any part of
the entire program, so why do we have higher-level languages at all?

> If one proposes limiting access of friend functions, one would also have to
> propose the same for all public member functions. No one ever proposes
> that, however.

This argument has always bothered me, because it seems to divide the world
into "perfect implementors" and "evil users" of classes.  That is, it seems
to suppose that anyone accessing the public interface is purposely malicious,
while those accessing the private parts will do no harm.

I use protected and private to protect myself from my own and others'
stupidity.  Its not malicious harm I'm worried about, it's inadvertent
harm.  I sometimes find myself forced to give another function or class
friend access to a class because it needs just one little piece of
information that it cannot otherwise obtain.  But I don't want to
inadvertently come along later and modify that friend function or class to
access or modify something I didn't mean for it to.

The problem is, since there is no way to *say* that in the language,
there's no way other than comments that I can even *document* my intention.
I much prefer code to comments, because I can believe the code but the
comments may be wrong.

> Personally, I don't see that this kind of fine-grained tweaking has any
> benefit. For one thing, why do you want to restrict access of a (member)
> function of your own class that you are writing? (Someone else might
> write it, but it is conceptually you writing it by proxy.)

Assuming I am the author of the entire program, why would I use protected
or private at all?  Why not just write the whole thing with global data
and forget classes entirely?

These features are useful because we find data abstraction to be a useful
tool to designing, writing, understanding, and maintaining large pieces of
software.  To me, that is really the only justification for language
features.  If we find it useful to have friend functions (or public static
member functions or whatever) that have limited access, then it is a
justifiable feature.  Since so many people request it, there must be some
demand for it.

> As a separate but related issue, many C++ experts now recommend against
> using protected members at all. The reasons for making something private
> are to hide implementation details that could be misused, and to allow a
> change in implementation details without affecting code in other modules.
>
> Making something public is a promise that the interface will be preserved.
>
> Making something protected means that you don't want to expose it to
> just anyone. Yet you cannot predict what classes will be derived from
> your class, or by whom, or under what circumstances. (Notice the contrast
> with friend functions: there are no friend functions except the ones
> you declare and write.) This means you cannot change the protected interface
> either. Further, you can no longer ensure that the protected interface will
> not be misused by the author of a derived class who did not understand the
> consistency requirements. You might as well make the thing public.

Again, this seems to divide the world into the "perfect implementors" and
"evil users" categories.  I find protected and private extremely useful,
especially in categorizing functions.  I very often design a set of classes
in which there are several protected functions (and sometimes data) that
derived classes may call, and private functions and data for use just
within that class.  This helps to document (and enforce) to myself and my
coworkers just what derived classes are expected to do and what they cannot
do, as well as documenting and enforcing the public interface.

The truth is, a class is too small an entity to embody a complete
subsystem, so we very often end up with groups of classes that are
interrelated and must cooperate to fulfill the design.  These groups of
classes may be related by inheritance or by being friends, or some of both.
Nevertheless, they are more closes related to each other than they are to
other classes and functions within the application as a whole.  The
language should recognize that.

--
Bill Leonard
Harris Computer Systems Corporation
2101 W. Cypress Creek Road
Fort Lauderdale, FL  33309
Bill.Leonard@mail.hcsc.com

These opinions and statements are my own and do not necessarily reflect the
opinions or positions of Harris Computer Systems Corporation.

------------------------------------------------------------------------------
More people run Windows on their home computers than on any other home
appliance.
------------------------------------------------------------------------------




Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 16 Feb 1995 23:12:19 GMT
Raw View
In article dca@hawk.csd.harris.com, bill@amber.ssd.csd.harris.com (Bill Leonard) writes:
>In article <3hu1g0$pea@engnews2.Eng.Sun.COM>, clamage@Eng.Sun.COM (Steve Clamage) writes:
>
>> If one proposes limiting access of friend functions, one would also have to
>> propose the same for all public member functions. No one ever proposes
>> that, however.
>
>This argument has always bothered me, because it seems to divide the world
>into "perfect implementors" and "evil users" of classes.  That is, it seems
>to suppose that anyone accessing the public interface is purposely malicious,
>while those accessing the private parts will do no harm.

That is certainly not how I meant it. My point was that there is nothing
special about friend functions as regards access rights. If it makes
sense to limit access of friend functions, the same arguments would apply to
any member function. I added the observation that although "protected friend
access" has been proposed informally several times, no one has proposed
"protected member access". To me, this indicates that the reasons for wanting
protected friend access haven't been thought through.

>  I sometimes find myself forced to give another function or class
>friend access to a class because it needs just one little piece of
>information that it cannot otherwise obtain.

That is often a symptom of a design error, either in the class or in
the client. Since one never gets the design right the first (or second)
time, the urge to add a friend solely for that purpose should be sublimated
into an urge to review the design, IMHO.

Friend functions and friend classes make perfect sense as part of the
public interface, or as part of the details of the implementation, or
because a design is best expressed as two or more cooperating classes.
IMHO, one needs to justify adding a friend at a late date (as opposed to
having made the friend part of the design) in those terms.
Having coded oneself into a corner is not a sufficient reason.

---
Steve Clamage, stephen.clamage@eng.sun.com






Author: bill@amber.ssd.csd.harris.com (Bill Leonard)
Date: 17 Feb 1995 16:15:34 GMT
Raw View
In article <3i0m4j$bfq@engnews2.Eng.Sun.COM>, clamage@Eng.Sun.COM (Steve Clamage) writes:
> In article dca@hawk.csd.harris.com, bill@amber.ssd.csd.harris.com (Bill Leonard) writes:
>>This argument has always bothered me, because it seems to divide the world
>>into "perfect implementors" and "evil users" of classes.  That is, it seems
>>to suppose that anyone accessing the public interface is purposely malicious,
>>while those accessing the private parts will do no harm.

> That is certainly not how I meant it. My point was that there is nothing
> special about friend functions as regards access rights. If it makes
> sense to limit access of friend functions, the same arguments would apply to
> any member function. I added the observation that although "protected friend
> access" has been proposed informally several times, no one has proposed
> "protected member access". To me, this indicates that the reasons for wanting
> protected friend access haven't been thought through.

I think friend *classes* are definitely different than static member
functions, in that two classes may cooperate to form a subsystem, yet each
class represents a distinct part of that subsystem.  The coupling among the
members of each class is thus, IMHO, stronger than the coupling between the
two classes.  Hence, the access one class has to the other should be less.

You said, "My point was that there is nothing special about friend
functions as regards access rights.", but that's merely stating the current
situation.  The question is, *should* there be a difference?  If the
language had been designed with a limited form of friendship to start with,
would you have argued the same?

> >  I sometimes find myself forced to give another function or class
> >friend access to a class because it needs just one little piece of
> >information that it cannot otherwise obtain.
>
> That is often a symptom of a design error, either in the class or in
> the client. Since one never gets the design right the first (or second)
> time, the urge to add a friend solely for that purpose should be sublimated
> into an urge to review the design, IMHO.

You may be right, in some cases, but we don't always have the luxury of
being able to redesign the software.  That doesn't mean one shouldn't at
least try to limit the effects of compromising design for function.

> Friend functions and friend classes make perfect sense as part of the
> public interface, or as part of the details of the implementation, or
> because a design is best expressed as two or more cooperating classes.
> IMHO, one needs to justify adding a friend at a late date (as opposed to
> having made the friend part of the design) in those terms.
> Having coded oneself into a corner is not a sufficient reason.

It doesn't have to be added "at a late date" to need limited access.  You
said that friends make sense as part of a design of cooperating classes.
Fine.  Why does that mean that the cooperating classes must have *complete*
access to all the other classes?  More than once I've wanted to give a
cooperating class access to a couple of protected functions that don't need
to be public but that *are* needed by the cooperating class.  But I can't
do that with the "all or nothing" friend feature.

Having said that, I'll say that I don't think the original proposal that
started this discussion is the right thing to do.  I'd much rather have a
way to "scope" a friend declaration.  For instance, suppose that we
invented a form of friend declaration that applied only from the point of
its occurrence until the next access keyword.  Example:

class A {
public:
   ...

protected:
   limited friend class B;

   void foo(int);

private:
   void bar(int);
}

In the above example, class B can only access function "foo" in class A.
(Note: This is not a proposal for specific syntax, just an illustration of
feature.)

--
Bill Leonard
Harris Computer Systems Corporation
2101 W. Cypress Creek Road
Fort Lauderdale, FL  33309
Bill.Leonard@mail.hcsc.com

These opinions and statements are my own and do not necessarily reflect the
opinions or positions of Harris Computer Systems Corporation.

------------------------------------------------------------------------------
More people run Windows on their home computers than on any other home
appliance.
------------------------------------------------------------------------------




Author: girod@dshp01.trs.ntc.nokia.com (Marc Girod)
Date: 17 Feb 1995 07:24:13 GMT
Raw View
To me this scheme makes sense in conjunction with the 'friend with
restrictions' proposal, e.g. as exposed in an other posting:

From: bvej18@phoney.boeing.com (Russ Gold)
Newsgroups: comp.std.c++
Subject: Proposal: friends with restrictions
Date: 15 Feb 1995 11:05:36 -0600
Message-ID: <9502151658.AA14730@phoney.he.boeing.com>

It is a convenience issue, since all this is doable now, although
doing it is heavy:

class Auser;

// Interface for a resource
class A {
  friend class Auser;
    virtual void foo_() = 0; //service for Ausers only
  // ...
};

// Interface for a server
class Auser {
  protected:
    virtual A& a() = 0; //implement this as you wish in a concrete mixin
    void foo() { a().foo_(); }
  // ...
};

This way, you actually define your A interface as a class to be
inherited, rather than as a public part of a class.

I stress that you write both classes, therefore you tightly control
your accesses.

Note that this scheme handles the concerns expressed in both
proposals.
--
+-----------------------------------------------------------------------------+
| Marc Girod - Nokia Telecommunications       Phone: +358-0-511 27703         |
| TL4E - P.O. Box 12                            Fax: +358-0-511 27432         |
| SF-02611 Espoo 61 - Finland              Internet: marc.girod@ntc.nokia.com |
|    X.400: C=FI, A=Elisa, P=Nokia Telecom, UNIT=TRS, SUR=Girod, GIV=Marc     |
+-----------------------------------------------------------------------------+




Author: jcox@splinter.coe.neu.edu (Jonathan J. Cox)
Date: 15 Feb 1995 20:06:16 GMT
Raw View
Proposal for New C++ Language Extension:    'protected friend'


I'm very interested in hearing what people have to say about this.
Please *post* your reply (my mailbox runneth over!).

   - Thanks in advance
----------------------------------------------------------------------


While ordinary friendship ('private friendship') grants access to the
protected and private sections of a class, 'protected friendship' would
only grant access to the protected section:

friend:     // current usage
private friend:    // NEW:  same as friend (i.e.: 'private' is implicit)
protected friend:  // NEW:  see below
public friend:    // NEW:  meaningless & harmless. No error or warning

EXAMPLE:

 class C
 {
  protected friend:
  C operator+(const  C &lhs, const C &rhs);
  // details omitted...
 };

The rules for placement and inheritance would be identical to that of the
unadorned keyword 'friend'  (now implicitly 'private friend').  Specifically,
   1)  Where you place the 'protected friendship' declaration within a class
       definition would make no difference at all.
 --> Whether you put a 'protected friendship' declaration in the
  public, protected, or private sections is irrelevant

 --> Whether you put the 'protected friendship' declaration before,
  in the middle of, or after the other declarations is
  irrelevant.

 2) Like ordinary (private) friendship, protected friendship would be
 non-transitive, and access could not be augmented in derived classes:

 If   class F is a 'protected friend' of class A,
 and  DF is publicly derived from F
 then   the only member fcns of DF that will be 'protected
   friends' of A are those DF inherits from F
   (and doesn't override).

USE:
The language extension would promote a private-data-only style
of class design by enabling non-class and non-related class functions
to use protected abstract interface functions (instead of manipulating
the representation directly).

Note that this would be a 100% compatible extension since old code that has
the keyword 'friend' following keyword 'protected' always has an imbedded
colon:
 protected :    friend class X;    // not  protected friend:  class X;


NEED:
See Meyer's Effective C++
 Item 18:  Strive for class interfaces that are complete  & minimal
 Item 20:  Avoid data in the public interface
It is desirable to keep data out of the protected interface for the same
reasons that it is desirable to keep it out of the public interface.
While it is possible to construct and enforce an abstract protected
interface to an underlying (private) rep for derivers, this is nearly
impossible to enforce with private friendship alone (see "RELATED IDEA"
below).

Protected friendship would avoid having to choose between :
     A) placing "dangerous" or implementation-driven accessor functions
 in the public interface

     B)  exposing EVERYTHING *including* private data to a friend

or   C)  The 'key class' idiom, which is ugly hard to maintain (see below)

=============================================

RELATED IDEA:      The "Key Class" Idiom    (ugh!)

class Foo
{
public:
  // ...
  class A
  {
  private:
    A() {}
    friend class Mumble; // access list for 'A' capability
  };
  class B
  {
  private:
    B() {}
    friend class Frotz;  // access list for 'B' capability
  };
private:
  // callable only by folks who can construct an A
  void tweedle(A&, other args...);

  // callable only by folks who can construct a B
  void dee(B&, other args...);

  // ... inaccessible private stuff
};


The nested classes A and B are "keys" that "unlock" the functions tweedle()
and dee(), respectively.  The A and B classes can individually list friends,
and therefore control who can call tweedle() and dee().  Since A and B are
empty and inline, its just a compiler crock without any runtime costs.

PROBLEM:
You have to remember to use the key-class interface when adding new functions
*AND* explain these gyrations (plus the arbitrary key name) to all who follow
in your footsteps.  This seems excessive for something as basic as granting
protected access.