Topic: Proposal for Standards Committee of C++: restricted friendship


Author: I V <ivlenin@gmx.co.uk>
Date: Fri, 3 May 2002 20:23:02 GMT
Raw View
On Fri, 19 Apr 2002 16:31:29 +0100, Hans Guijt wrote:
> class peon;
>
> class manager {
>     public:
>         SomePublicFunction_1(...);
>         SomePublicFunction_2(...)
>
>     interface peon:
>         DoSomethingForPeon_1(peon *, ...);
>         DoSomethingForPeon_2(peon *, ...);
>
>     private:
>         ...
> };

Could one do:

class manager
{
     public:
        friend class peon_inteface
        {
     friend class peon;

            void DoSomethingForPeon(manager& m, peon * p)
  { m.DoSomethingForPeon_Impl(p); }
 };

     private:
         void DoSomethingForPeon_Impl(peon *);

};

This suggestion isn't supposed to show your proposal isn't a good one (on
grounds of elegance or clearness of intent, perhaps), but it occoured to
me as an obvious solution, and I'd be grateful if anyone would tell me if
it works or not.

--
"Mr I V Lenin, the Lenin of love,
 Make me feel so fine,
 With a hit of socialism,
 Straight in the mainline."     -- Rev Dr D Wayne Love

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Garry Lancaster" <glancaster@ntlworld.com>
Date: Thu, 25 Apr 2002 17:38:46 GMT
Raw View
Javier Estrada:
> There is a third choice that let's you have your cake and eat it too.
> The solution to this "partial friendship" you're describing is at:
>
> http://www.objectmentor.com/publications/privateInterface.pdf.
>
> Actually, you were almost there.  In a nutshell, you refactor the
> functions that you want to offer to the peon class and inherit
> *privately* from it.  Then you pass a pointer or reference to the peon
> class (usually in its constructor or a mutator).  For example:
>
> class peons_only
> {
>   public:
>     virtual void foo() = 0;
>     virtual void bar() = 0;
> };
>
> class peon
> {
>   peons_only *m_po;
>
>   public:
>     peon(peons_only *po) : m_po(po) {}
>
>   // now peon can access whatever peons_only can do
>   // by invoking functions on m_po.
>
> };
>
> class manager : private peons_only
> {
>   public:
>     manager() {
>       // create peons and grant them access to peons_only interface
>       // (let's leak memory on the pointers on purpose :-)
>       peon *pp1 = new peon(this);
>       peon *pp2 = new peon(this);
>       peon *pp3 = new peon(this);
>     }
>
>   private:
>     // Accessible only to peons
>     void foo() {}
>     void bar() {}
> };

Neat. The downside is that the "partially friendly"
functions have to be virtual so there is likely to
be some runtime overhead to this technique.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Hans Guijt" <hguijt@inter.nl.net>
Date: Mon, 29 Apr 2002 16:58:50 GMT
Raw View
"Javier Estrada" <ljestrada@hotmail.com> schreef in bericht
news:d522680b.0204232313.5ad00113@posting.google.com...
> > I would like to be able to express a 'partial friendship', perhaps
expressed
> > as follows:
> >
> > class peon;
> >
> > class manager {
> >     public:
> >         SomePublicFunction_1(...);
> >         SomePublicFunction_2(...)
> >
> >     interface peon:
> >         DoSomethingForPeon_1(peon *, ...);
> >         DoSomethingForPeon_2(peon *, ...);
> >
> >     private:
> >         ...
> > };
> >
>
> There is a third choice that let's you have your cake and eat it too.
> The solution to this "partial friendship" you're describing is at:
>
> http://www.objectmentor.com/publications/privateInterface.pdf.
>
> Actually, you were almost there.  In a nutshell, you refactor the
> functions that you want to offer to the peon class and inherit
> *privately* from it.  Then you pass a pointer or reference to the peon
> class (usually in its constructor or a mutator).  For example:
>
> class peons_only
> {
>   public:
>     virtual void foo() = 0;
>     virtual void bar() = 0;
> };
>
> class peon
> {
>   peons_only *m_po;
>
>   public:
>     peon(peons_only *po) : m_po(po) {}
>
>   // now peon can access whatever peons_only can do
>   // by invoking functions on m_po.
>
> };
>
> class manager : private peons_only
> {
>   public:
>     manager() {
>       // create peons and grant them access to peons_only interface
>       // (let's leak memory on the pointers on purpose :-)
>       peon *pp1 = new peon(this);
>       peon *pp2 = new peon(this);
>       peon *pp3 = new peon(this);
>     }
>
>   private:
>     // Accessible only to peons
>     void foo() {}
>     void bar() {}
> };

Interesting. This does indeed provide a solution for partial friendship. But
if I may raise one criticism to this method (nag, nag ;-) ), I think that
the code above tends to obscure the relationship between the classes: I need
to look carefully at the code to understand the special privileges of class
peon instead of reading it directly from the class definition.


Regards,

Hans Guijt




---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: rhairgroveNoSpam@Pleasebigfoot.com (Bob Hairgrove)
Date: Mon, 22 Apr 2002 19:28:31 GMT
Raw View
On Fri, 19 Apr 2002 09:31:29 CST, "Hans Guijt" <hguijt@inter.nl.net>
wrote:

>Introduction
>------------
>
>I often find myself in a situation where I have two classes that have a
>special relationship. Typically (but not always), the classes are of the
>controller / controllee type, with one controller that is in charge of
>numerous controllees. The controller has a public interface, but also has
>functions specifically to handle requests by the controllees.
>
>The C++ language offers me essentially two choices to specify this last
>group of functions. The first choice is to declare them publicly, and risk
>they will be called from anywhere else within the program. More often than
>not this is undesirable, since such functions are meant only for use within
>the context of controller / controllee interaction, and should be considered
>'private to the pair of classes'.
>
>The second choice is to declare the functions privately. This forces me to
>make the controllees a friend of the controller. Again, this is undesirable
>because I do not want the controllees to have knowledge of the controller -
>they should be restricted to the interface I have provided with the
>functions.
>
>Example:
>
>class peon;
>
>class manager {
>    public:
>        // functions for clients of 'manager'
>
>        SomePublicFunction_1(...);
>        SomePublicFunction_2(...)
>
>        // functions only for class 'peon'
>
>        DoSomethingForPeon_1(peon *, ...);
>        DoSomethingForPeon_2(peon *, ...);
>
>    private:
>        ...
>};
>

Have you read "Design Patterns" by Gamma (et al.), as well as "Pattern
Hatching" (I forget the author of that one)? There are interesting
chapters concerning the Observer pattern which seem to fit in with the
scope of problems you address here. In particular, there is a chapter
in "Pattern Hatching" called "The Problem with Observer" or something
of that nature ... perhaps this would have some bearing on the issue?

>Proposed solution for this problem
>-----------------------------------
>
>I would like to be able to express a 'partial friendship', perhaps expressed
>as follows:
>
>class peon;
>
>class manager {
>    public:
>        SomePublicFunction_1(...);
>        SomePublicFunction_2(...)
>
>    interface peon:
>        DoSomethingForPeon_1(peon *, ...);
>        DoSomethingForPeon_2(peon *, ...);
>
>    private:
>        ...
>};
>
>The phrase 'interface <classname>:' means that only member functions of
>class <classname> may call the functions listed in that section. This is
>conceptually similar to how protected: and private: limit access to members
>in their sections. In the example, only member functions of class peon are
>allowed to call the DoSomethingForPeon() functions.
>

You might be able to achieve the same with a Proxy class. Later on in
your message, you mention such a possible solution using "intermediate
classes". The advantage of a proxy class is that it can be transparent
to clients. IMHO this offers the developer far greater control over
access levels than yet another kind of "protected" access. As far as
"elegance", if clients know nothing of their existence, you have
already achieved the epitome of elegance.

>The advantages of having limited friendship would be:
>
>- it limits the needs for both 'friend' and redundant 'public' declarations.
>
>- it allows the programmer to establish (and document on code level) class
>patterns in his code.
>
>
>Some afterthoughts
>-------------------
>
>- I spotted another proposal in this newsgroup for a language extension that
>also uses the 'interface' keyword. I do not mean to steal mr. Pizarro's
>keyword, but cannot think of a better keyword for the proposal described
>here.
>
>- I have observed that the functions I would like to place in an 'interface'
>block typically take a pointer to the object that is calling the function
>(i.e. a 'this' pointer) as one of their parameters (in the example above,
>the DoSomethingForPeon() functions each take a peon* as a parameter). Given
>the fact that the interface block guarantees the existence and the type of
>the 'this' pointer of the calling object, it only makes sense to make this
>information available to the called function, similar to how 'this' is
>always implicitly available. In order to preserve symmetry, I believe such a
>pointer should be called a 'that' pointer.
>

You could achieve the same with a reference, or not?

>- It may be desirable to allow further qualification of the interface block
>by allowing either a 'private interface' or a 'protected interface'. The
>difference would be that a private interface can only be called from the
>class specified in the interface declaration (and not its children), whereas
>a protected interface may also be called from those children.
>
>- One criticism that could be levelled at this mechanism is that it is
>somewhat redundant: C++ has other methods to express contracts, such as
>intermediate classes. In defence I would say that such methods are clumsy
>and inelegant compared to this solution. Also, I believe that class
>relationships are such a fundamental part of software design that having an
>elegant way to express them in your language is a desirable property.


Bob Hairgrove
rhairgroveNoSpam@Pleasebigfoot.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Hans Guijt" <hguijt@inter.nl.net>
Date: Fri, 19 Apr 2002 09:31:29 CST
Raw View
Introduction
------------

I often find myself in a situation where I have two classes that have a
special relationship. Typically (but not always), the classes are of the
controller / controllee type, with one controller that is in charge of
numerous controllees. The controller has a public interface, but also has
functions specifically to handle requests by the controllees.

The C++ language offers me essentially two choices to specify this last
group of functions. The first choice is to declare them publicly, and risk
they will be called from anywhere else within the program. More often than
not this is undesirable, since such functions are meant only for use within
the context of controller / controllee interaction, and should be considered
'private to the pair of classes'.

The second choice is to declare the functions privately. This forces me to
make the controllees a friend of the controller. Again, this is undesirable
because I do not want the controllees to have knowledge of the controller -
they should be restricted to the interface I have provided with the
functions.

Example:

class peon;

class manager {
    public:
        // functions for clients of 'manager'

        SomePublicFunction_1(...);
        SomePublicFunction_2(...)

        // functions only for class 'peon'

        DoSomethingForPeon_1(peon *, ...);
        DoSomethingForPeon_2(peon *, ...);

    private:
        ...
};

Proposed solution for this problem
-----------------------------------

I would like to be able to express a 'partial friendship', perhaps expressed
as follows:

class peon;

class manager {
    public:
        SomePublicFunction_1(...);
        SomePublicFunction_2(...)

    interface peon:
        DoSomethingForPeon_1(peon *, ...);
        DoSomethingForPeon_2(peon *, ...);

    private:
        ...
};

The phrase 'interface <classname>:' means that only member functions of
class <classname> may call the functions listed in that section. This is
conceptually similar to how protected: and private: limit access to members
in their sections. In the example, only member functions of class peon are
allowed to call the DoSomethingForPeon() functions.

The advantages of having limited friendship would be:

- it limits the needs for both 'friend' and redundant 'public' declarations.

- it allows the programmer to establish (and document on code level) class
patterns in his code.


Some afterthoughts
-------------------

- I spotted another proposal in this newsgroup for a language extension that
also uses the 'interface' keyword. I do not mean to steal mr. Pizarro's
keyword, but cannot think of a better keyword for the proposal described
here.

- I have observed that the functions I would like to place in an 'interface'
block typically take a pointer to the object that is calling the function
(i.e. a 'this' pointer) as one of their parameters (in the example above,
the DoSomethingForPeon() functions each take a peon* as a parameter). Given
the fact that the interface block guarantees the existence and the type of
the 'this' pointer of the calling object, it only makes sense to make this
information available to the called function, similar to how 'this' is
always implicitly available. In order to preserve symmetry, I believe such a
pointer should be called a 'that' pointer.

- It may be desirable to allow further qualification of the interface block
by allowing either a 'private interface' or a 'protected interface'. The
difference would be that a private interface can only be called from the
class specified in the interface declaration (and not its children), whereas
a protected interface may also be called from those children.

- One criticism that could be levelled at this mechanism is that it is
somewhat redundant: C++ has other methods to express contracts, such as
intermediate classes. In defence I would say that such methods are clumsy
and inelegant compared to this solution. Also, I believe that class
relationships are such a fundamental part of software design that having an
elegant way to express them in your language is a desirable property.


Hans Guijt
hguijt@inter.nl.net




---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: ljestrada@hotmail.com (Javier Estrada)
Date: Wed, 24 Apr 2002 16:07:14 GMT
Raw View
> I often find myself in a situation where I have two classes that have a
> special relationship. Typically (but not always), the classes are of the
> controller / controllee type, with one controller that is in charge of
> numerous controllees. The controller has a public interface, but also has
> functions specifically to handle requests by the controllees.
>
> The C++ language offers me essentially two choices to specify this last
> group of functions. The first choice is to declare them publicly, and risk
> they will be called from anywhere else within the program. More often than
> not this is undesirable, since such functions are meant only for use within
> the context of controller / controllee interaction, and should be considered
> 'private to the pair of classes'.
>
> The second choice is to declare the functions privately. This forces me to
> make the controllees a friend of the controller. Again, this is undesirable
> because I do not want the controllees to have knowledge of the controller -
> they should be restricted to the interface I have provided with the
> functions.
>
> Example:
>
> class peon;
>
> class manager {
>     public:
>         // functions for clients of 'manager'
>
>         SomePublicFunction_1(...);
>         SomePublicFunction_2(...)
>
>         // functions only for class 'peon'
>
>         DoSomethingForPeon_1(peon *, ...);
>         DoSomethingForPeon_2(peon *, ...);
>
>     private:
>         ...
> };
>
> Proposed solution for this problem
> -----------------------------------
>
> I would like to be able to express a 'partial friendship', perhaps expressed
> as follows:
>
> class peon;
>
> class manager {
>     public:
>         SomePublicFunction_1(...);
>         SomePublicFunction_2(...)
>
>     interface peon:
>         DoSomethingForPeon_1(peon *, ...);
>         DoSomethingForPeon_2(peon *, ...);
>
>     private:
>         ...
> };
>

There is a third choice that let's you have your cake and eat it too.
The solution to this "partial friendship" you're describing is at:

http://www.objectmentor.com/publications/privateInterface.pdf.

Actually, you were almost there.  In a nutshell, you refactor the
functions that you want to offer to the peon class and inherit
*privately* from it.  Then you pass a pointer or reference to the peon
class (usually in its constructor or a mutator).  For example:

class peons_only
{
  public:
    virtual void foo() = 0;
    virtual void bar() = 0;
};

class peon
{
  peons_only *m_po;

  public:
    peon(peons_only *po) : m_po(po) {}

  // now peon can access whatever peons_only can do
  // by invoking functions on m_po.

};

class manager : private peons_only
{
  public:
    manager() {
      // create peons and grant them access to peons_only interface
      // (let's leak memory on the pointers on purpose :-)
      peon *pp1 = new peon(this);
      peon *pp2 = new peon(this);
      peon *pp3 = new peon(this);
    }

  private:
    // Accessible only to peons
    void foo() {}
    void bar() {}
};


Regards,

Javier

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]