Topic: proposal: acquaintance


Author: allan_w@my-dejanews.com (Allan W)
Date: Thu, 13 Feb 2003 21:04:23 +0000 (UTC)
Raw View
barfurth@gmx.net (Joerg Barfurth) wrote
> Hi Allan,
>
> Allan W <allan w@my-dejanews.com> wrote:
>
> > barfurth@gmx.net (Joerg Barfurth) wrote
> > > A Cappella Guy <acappellaguy@hotmail.com> wrote:
> > > > class Foo {
> > > >    void privateMethod();
> > > > };
> > > >
> > > > struct Evil  {
> > Evil was supposed to derive from Foo:
> >     struct Evil : private Foo {
> > > >    void privateMethod();
> > > > };
>
> That does not change the argument. 'privateMethod' in fact is. No method
> of another class (not even one derived from Foo) can access it legally.

You're right of course. The discussion had previously discussed protected
members. I guess I read too quickly, and assumed that "privateMethod"
was actually a "protectedMethod."

> > > > int main() {
> > > >    Foo* foo = new Foo;
> > > >    Evil* evil = reinterpret cast<Evil*>foo;
> > > >    evil->privateMethod();
> > > > }
>
> Here the intent seems to be that this should *directly* call
> Foo::privateMethod (as any indirect call would meet the original problem
> soon).

Yes, clearly.

> > > And I know no implementation where this
> > > would work as intended. With some implementations it will execute
> > > Evil::privateMethod with 'this' pointing to the memory of *foo,  but
>  I
> > > know of no case where it would result in calling Foo::privateMethod.
> >
> > You're missing the point -- you get to implement Evil::privateMethod.
> >
> >     void Evil::privateMethod() { Foo::privateMethod(); }
>
> No access to private member Foo::privateMethod() ....

Right.

> > > This might be different, if the method were virtual (in both classes)
>  ,
> > > but it  would still be undefined behavior.
> >
> > Making it virtual in both classes wouldn't help at all. The
> > reinterpret cast in main won't change the vtable pointer in the Foo
> > object.
>
> That is the point! The idea was to make Evil (which must *not* derive
> from Foo) sufficiently similar to Foo to have the same layout and to
> have privateMethod in the same vtable slot. Then the reinterpret cast
> might yield an Evil*, that points at an object having the vtable pointer
> of a Foo. So the call would indeed invoke Foo::privateMethod (via the
> vtable) and if the object representations of Evil* and Foo* are the
> same, then the method might even recieve a valid this pointer.
>
> Of course this breaks (among other more low-level possibilities), if the
> compiler can determine that no actual virtual dispatch is needed and
> directly calls  Evil::privateMethod. (It could do that in the very
> simple test case above, as there is no class in the entire program, that
> derives from Evil).
>
> Again:  that is what I expect from undefined behavior  ...

Even if you really _have_ to invoke undefined behavior, there are less
fragile (but still fragile) ways to do it.

The easiest way would probably be to hack the header file that defines
Foo, and add "public:" in the appropriate place. Not guaranteed to
work with seperate compilation, because the compiler is free to
rearrange classes when there's an intervening access specifier; but I
suspect it would work on almost every compiler anyway.

When people say that C++ was designed to prevent against accidents but not
fraud -- this is the fraud referred to.

---
[ 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: allan_w@my-dejanews.com (Allan W)
Date: Wed, 5 Feb 2003 22:10:38 +0000 (UTC)
Raw View
barfurth@gmx.net (Joerg Barfurth) wrote
> A Cappella Guy <acappellaguy@hotmail.com> wrote:
> > class Foo {
> >    void privateMethod();
> > };
> >
> > struct Evil  {
Evil was supposed to derive from Foo:
    struct Evil : private Foo {
> >    void privateMethod();
> > };
> >
> > int main() {
> >    Foo* foo = new Foo;
> >    Evil* evil = reinterpret_cast<Evil*>foo;
> >    evil->privateMethod();
> > }
>
> This is undefined behavior.

True.

> And I know no implementation where this
> would work as intended. With some implementations it will execute
> Evil::privateMethod with 'this' pointing to the memory of *foo,  but I
> know of no case where it would result in calling Foo::privateMethod.

You're missing the point -- you get to implement Evil::privateMethod.

    void Evil::privateMethod() { Foo::privateMethod(); }

> This might be different, if the method were virtual (in both classes),
> but it  would still be undefined behavior.

Making it virtual in both classes wouldn't help at all. The
reinterpret_cast in main won't change the vtable pointer in the Foo
object.

---
[ 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: allan_w@my-dejanews.com (Allan W)
Date: Wed, 5 Feb 2003 23:29:38 +0000 (UTC)
Raw View
> <danielgutson@hotmail.com> wrote
> > First, the classification of 'public, protected, private' is
> > accessibility in terms of INHERITANCE.

ndenville@jands.com.au ("Nick Denville") wrote
> I have to disagree - 'public' and 'private' are used, respecitively, to
> specify a class's public interface and to hide/secure it's implementation -
> whether this is within an inheritance heirarchy or not is somewhat
> irrelevant. Sure, 'protected' only has relevance when subclassing, but the
> crux of my original problem is that 'friend' is a sledgehammer solution when
> 'public' isn't good enough for the interaface between unrelated classes.

Please read Scott Meyer's books, "Effective C++" and "More Effective C++".
One of the books (I'm sorry, I forget which one) specifically discusses
the issue, including a technique that exposes some but not all functions
to code outside of the class heirarchy.

Buy two copies of each. Hide one copy and read it! Leave one on your desk
until it's stolen; then bring out the other one, and buy yourself another
copy to hide. If your peers steal a copy, they'll probably read it, and
your whole organization will improve.

---
[ 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: allan_w@my-dejanews.com (Allan W)
Date: Thu, 6 Feb 2003 00:55:44 +0000 (UTC)
Raw View
> acappellaguy@hotmail.com (A Cappella Guy) writes:
> > * - Note the spelling.  Acquaintance is not the easiest word in the
> > language to spell.  And though I'm sure most C++ users would quickly
> > learn the proper spelling, it's less wieldy than "guest" or something
> > shorter.

llewelly.@@xmission.dot.com (llewelly) wrote
> I don't see a great need for the 'acquaintance' feature, but I think
>     the difficulty of spelling acquaintance is a good thing, if it is
>     to be a new reserved word. It's unwieldiness means it will have
>     been used as an identifier much less often.

I'm pretty sure that was the motivation behind the naming of the keyword
friend. I mean, we all know that the "i before e" rule has exceptions,
such as "when sounding like 'a' as in 'neighbor' and 'weigh'." Depending
on your accent, 'friend' could sound like 'weigh'. Besides, there are
also other exceptions, such as 'weird'. So it would be natural for people
to be confused about how to spell 'friend', and thus they were unlikely
to use it as an identifier.

Contrast that to the keyword 'do' which is not only easy to spell,
but it's used in ordinary English quite often. It's also only one
letter away from other words commonly used as identifiers: 'to',
'go', and 'no' come to mind. I understand that Kernigan and Ritchie
both supported using 'do'. What were they all thinking?!?

While we're at it, what made anyone think that four different pairs
of grouping operators should all mean something different?
    () -- expression grouping
    <> -- template grouping (this is NOT the "not equal" operator!)
    [] -- index group
    {} -- statement grouping
I would suggest that we make all four of these synonymous, but it's
far too late for that -- there are already classes that overload
both operator[] and operator() to do different things, and such a
change would break that code. Still, we ought to at least be
consistent -- the next standard ought to allow us to overload the
other two as well.

    struct foo {
        bool operator{}(int i) { std::cout << i; return true;  }
        bool operator<>(int j) { std::cout << j << std::endl; return false; }
        void operator+(foo&) {}
    };
    int main() {
        foo so, no, go, yo;
        if so { 25; } do no+yo; while { go<13> );                     // :-)
    }
Should write "2513" to standard output.

---
[ 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: barfurth@gmx.net (Joerg Barfurth)
Date: Thu, 6 Feb 2003 00:56:14 +0000 (UTC)
Raw View
Hi Allan,

Allan W <allan_w@my-dejanews.com> wrote:

> barfurth@gmx.net (Joerg Barfurth) wrote
> > A Cappella Guy <acappellaguy@hotmail.com> wrote:
> > > class Foo {
> > >    void privateMethod();
> > > };
> > >=20
> > > struct Evil  {
> Evil was supposed to derive from Foo:
>     struct Evil : private Foo {
> > >    void privateMethod();
> > > };

That does not change the argument. 'privateMethod' in fact is. No method
of another class (not even one derived from Foo) can access it legally.

> > > int main() {
> > >    Foo* foo =3D new Foo;
> > >    Evil* evil =3D reinterpret_cast<Evil*>foo;
> > >    evil->privateMethod();
> > > }

Here the intent seems to be that this should *directly* call
Foo::privateMethod (as any indirect call would meet the original problem
soon).

> > And I know no implementation where this
> > would work as intended. With some implementations it will execute
> > Evil::privateMethod with 'this' pointing to the memory of *foo,  but =
I
> > know of no case where it would result in calling Foo::privateMethod.
>=20
> You're missing the point -- you get to implement Evil::privateMethod.
>=20
>     void Evil::privateMethod() { Foo::privateMethod(); }

No access to private member Foo::privateMethod() ....
=20
> > This might be different, if the method were virtual (in both classes)=
,
> > but it  would still be undefined behavior.
>=20
> Making it virtual in both classes wouldn't help at all. The
> reinterpret_cast in main won't change the vtable pointer in the Foo
> object.

That is the point! The idea was to make Evil (which must *not* derive
from Foo) sufficiently similar to Foo to have the same layout and to
have privateMethod in the same vtable slot. Then the reinterpret_cast
might yield an Evil*, that points at an object having the vtable pointer
of a Foo. So the call would indeed invoke Foo::privateMethod (via the
vtable) and if the object representations of Evil* and Foo* are the
same, then the method might even recieve a valid this pointer.

Of course this breaks (among other more low-level possibilities), if the
compiler can determine that no actual virtual dispatch is needed and
directly calls  Evil::privateMethod. (It could do that in the very
simple test case above, as there is no class in the entire program, that
derives from Evil).

Again:  that is what I expect from undefined behavior  ...

Regards, Joerg

--=20
J=F6rg Barfurth                         barfurth@gmx.net
<<<<<<<<<<<<< using std::disclaimer;  <<<<<<<<<<<<<<<<<<<<<<<<<<<<
Software Developer                    http://util.openoffice.org
StarOffice Configuration    # Deutsch:http://de.openoffice.org

---
[ 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: barfurth@gmx.net (Joerg Barfurth)
Date: Sun, 2 Feb 2003 18:14:56 +0000 (UTC)
Raw View
A Cappella Guy <acappellaguy@hotmail.com> wrote:

> For that matter, you can use private methods a la:
>=20
> class Foo {
>    void privateMethod();
> };
>=20
> struct Evil {
>    void privateMethod();
> };
>=20
> int main() {
>    Foo* foo =3D new Foo;
>    Evil* evil =3D reinterpret_cast<Evil*>foo;
>    evil->privateMethod();
> }

This is undefined behavior. And I know no implementation where this
would work as intended. With some implementations it will execute
Evil::privateMethod with 'this' pointing to the memory of *foo,  but I
know of no case where it would result in calling Foo::privateMethod.
This might be different, if the method were virtual (in both classes),
but it  would still be undefined behavior.

Ciao, Joerg


--=20
J=F6rg Barfurth                         barfurth@gmx.net
<<<<<<<<<<<<< using std::disclaimer;  <<<<<<<<<<<<<<<<<<<<<<<<<<<<
Software Developer                    http://util.openoffice.org
StarOffice Configuration    # Deutsch:http://de.openoffice.org

---
[ 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: barfurth@gmx.net (Joerg Barfurth)
Date: Sun, 2 Feb 2003 18:14:55 +0000 (UTC)
Raw View
"Nick Denville" <ndenville@jands.com.au> wrote:

> I often find that it would be highly desirable to expose only a subset =
of a
> class's non-public members to a nominated class. I dislike using 'frien=
d'
> for this purpose because it doesn't allow any selectivity as to what ge=
ts
> exposed, unlike using 'protected' to selectively expose to a derived cl=
ass.

Well, I normally consider friends to be part of the implementation.
There are plenty of reasons to avoid long-distance friendship.

But if the friend is part of my implementation, then I get to determine
what the friend does (and what members it uses for that purpose).

For selectively handing out access to partial interfaces privately
inheriting from an abstract interface seems to be the better choice.

But if you still think you need that feature, you can do that today.

> class Something
> {
>     friend class Risky; // give access to all of my stuff to Risky clas=
s
>     public:
>         Something();
>     protected:
>         void doSomethingSpecial();
>     private:
>         void forInternalUseOnly();
>  // aquaintance class Trusted;=20
>  // give access to only my protected members to Trusted class
      public:
          class KeyToSomethingSpecial
          {
             friend class Trusted;
             KeyToSomethingSpecial() {}
          };
          void restrictedSomethingSpecial(KeyToSomethingSpecial)
          { this->doSomethingSpecial(); }
> };

You can use one such key class for several members and/or you can enable
multiple acquainted classes to access the same set of members through
one key class. You can get rid of the inline forwarding function, if you
use the tagged interface even inside your class.

Ciao, Joerg

Note: If you want to disable some evil tricks, the copy-c'tor of the key
class needs to be private as well. (Stuff like Key k =3D k;).

--=20
J=F6rg Barfurth                         barfurth@gmx.net
<<<<<<<<<<<<< using std::disclaimer;  <<<<<<<<<<<<<<<<<<<<<<<<<<<<
Software Developer                    http://util.openoffice.org
StarOffice Configuration    # Deutsch:http://de.openoffice.org

---
[ 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: barfurth@gmx.net (Joerg Barfurth)
Date: Mon, 3 Feb 2003 19:57:18 +0000 (UTC)
Raw View
"Nick Denville" <ndenville@jands.com.au> wrote:

> To be honest, I wasn't aware that such a technique would work - it seem=
s
> that this would allow someone to break privacy of a class (at least to =
the
> protected level) without the consent of that class (presuming this is w=
hat
> you meant?):

Well, it  doesn't work (presuming the following is what was meant).

> class Something
> {
> public:
>     Something(): _x(5) {}
> protected:
>     int x() {return _x;}
> private:
>     int _x;
> };
>=20
> class Introducer: public Something
> {
>     friend class Guest;
> };
>=20
> class Guest
> {
> public:
>     void accessSomething(Something& s);
> };
>=20
> void Guest::accessSomething(Something& s)
> {
>     ((Introducer&)s).x();
> }

The member access here produces undefined behavior, unless the Object
bound to s actually is an instance of Introducer. Thus:

int main()
{
   Introducer i;
   Guest().accessSomething(i); // OK

   Something s;
   Guest().accessSomething(s); // undefined behavior

   struct Derived : Something {} d;
   Guest().accessSomething(d); // undefined  behavior
}

Ciao,  Joerg

--=20
J=F6rg Barfurth                         barfurth@gmx.net
<<<<<<<<<<<<< using std::disclaimer;  <<<<<<<<<<<<<<<<<<<<<<<<<<<<
Software Developer                    http://util.openoffice.org
StarOffice Configuration    # Deutsch:http://de.openoffice.org

---
[ 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: ndenville@jands.com.au ("Nick Denville")
Date: Tue, 28 Jan 2003 04:05:58 +0000 (UTC)
Raw View
<danielgutson@hotmail.com> wrote in message
news:23478c42.0301241625.7181d7ee@posting.google.com...
> Ok. Let's go by steps.
> First, the classification of 'public, protected, private' is
> accessibility in terms of INHERITANCE.

I have to disagree - 'public' and 'private' are used, respecitively, to
specify a class's public interface and to hide/secure it's implementation -
whether this is within an inheritance heirarchy or not is somewhat
irrelevant. Sure, 'protected' only has relevance when subclassing, but the
crux of my original problem is that 'friend' is a sledgehammer solution when
'public' isn't good enough for the interaface between unrelated classes.




---
[ 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: ndenville@jands.com.au ("Nick Denville")
Date: Tue, 28 Jan 2003 13:08:30 +0000 (UTC)
Raw View
"Dave Harris" <brangdon@cix.co.uk> wrote in message
news:memo.20030124135436.17371B@brangdon.madasafish.com...
> On the syntax side, I'd consider using some combination of existing
> keywords for this. Eg:
>
>      class Something {
>          protected friend class Trusted;
>          // ...
>      };
>
> So that plain "friend" would be equivalent to "private friend".

Yes - that makes a lot of sense.


> Anyway, here is another inheritance idiom (which at the time of posting is
> different to those already here).
>
>     class Trusting {
>         class FriendInterface;
>         friend class FriendInterface;
>         int data;
>         // ...
>     };
>
>     class Trusting::FriendInterface {
>     protected:
>         int GetData( const Trusting &t ) const {
>             return t.data;
>         }
>         SetData( Trusting &t, int d ) {
>             t.data = d;
>         }
>     };
>
>     class Trusted : private Trusting::FriendInterface {
>         void use( Trusting &t ) {
>             // int data = t.data;
>             int data = GetData( t );
>         }
>     };
>

A relatively minor downside of this is that anything can inherit from
FriendInterface and get access without Trusting's consent. However, if the
members of FriendInterface were private instead of public, FriendInterface
could nominate trusted classes via 'friend' - which would pretty much
achieve what I desire, although with a little bit of extra typing ;-)
Anyway - thanks, that's a useful idiom.



---
[ 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: danielgutson@hotmail.com (danielgutson@hotmail.com)
Date: Wed, 29 Jan 2003 07:35:03 +0000 (UTC)
Raw View
ndenville@jands.com.au ("Nick Denville") wrote in message news:<b14uvc$2eh$1@merki.connect.com.au>...
> <danielgutson@hotmail.com> wrote in message
> news:23478c42.0301241625.7181d7ee@posting.google.com...
> > Ok. Let's go by steps.
> > First, the classification of 'public, protected, private' is
> > accessibility in terms of INHERITANCE.
>
> crux of my original problem is that 'friend' is a sledgehammer solution when
> 'public' isn't good enough for the interaface between unrelated classes.

that's why I suggested restricting 'public' instead of 'enhancing
friend' (enhancing in terms of accessibility control, not in
'visibility').

So you could have

  namespace:

which is more restrictive than public (conceptually, it would be
public || namespace, equal to namespace).

or even more restrictive,

  protected || namespace:

Daniel.


>
>
>
>
> ---
> [ 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                       ]

---
[ 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: francis.glassborow@ntlworld.com (Francis Glassborow)
Date: Mon, 27 Jan 2003 20:27:06 +0000 (UTC)
Raw View
In article <b0o2il$kio$1@merki.connect.com.au>, Nick Denville
<ndenville@jands.com.au> writes
>I often find that it would be highly desirable to expose only a subset of a
>class's non-public members to a nominated class. I dislike using 'friend'
>for this purpose because it doesn't allow any selectivity as to what gets
>exposed, unlike using 'protected' to selectively expose to a derived class.
>I would like to propose the addition of the 'aquaintance' keyword to
>complement 'friend', which would allow access to the protected members,

What is wrong with using a nested private struct to subset the
non-public interface which can include friend declarations of other
functions/classes?

Perhaps we need to tweak the Standard a little to make that work, but if
there really is a need to provide this kind of limited friendship (which
I doubt) then it would be doable.


--
ACCU Spring Conference 2003 April 2-5
The Conference you cannot afford to miss
Check the details: http://www.accuconference.co.uk/
Francis Glassborow      ACCU

---
[ 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: allan_w@my-dejanews.com (Allan W)
Date: Mon, 27 Jan 2003 22:57:39 +0000 (UTC)
Raw View
> > Nick Denville <ndenville@jands.com.au> wrote:
> > > I often find that it would be highly desirable to expose
> > > only a subset of a class's non-public members to a
> > > nominated class. I dislike using 'friend'

> "A Cappella Guy" <acappellaguy@hotmail.com> wrote
> > I'm not sure that overloading the protected keyword is the
> > best way to go about this.  I'm sure I could come up with
> > an example of a class that intends an entirely different
> > subset of functionality to be exposed to subclasses and
> > acquaintances*.
> >
> > What you want can be accomplished now via inheritance:

ndenville@jands.com.au ("Nick Denville") wrote
> Thanks for your reply. I agree that the proposed solution is
> not as flexible as some may desire, but it does, however,
> afford much more flexibility than using 'friend'.
>
> I was prompted to suggest this to the group when considering
> a somewhat 'component-centric' design decomposition. The design
> in question involves a group of classes that each encapsulate a
> portion of the implementation of an enclosing class, and are
> entitled access to parts of the implementation of that class.
> I'm not sure that an inheritance-based solution would do the
> trick for me, and in any case it is less wieldy than simply
> using 'friend'.

I'm not supposed to tell anyone this, but you've almost guessed
it anyway. The next version of C++ is going to have complete
Access Control Lists (ACL), borrowed from Microsoft Windows NT,
which was itself borrowwed from Digital Equipment's VAX/VMS
(and I would only be mildly surprised to find out that DEC
borrowed it from someone else -- maybe Xerox PARC? They create
a whole lot of things there...).

Some of the more complicated syntax issues are still being worked
out, but here are the overall semantics.

Every single "thing" in the system (class, instantiation,
global function, member function, even library objects) gets a PUID
(Program Unique Identification), which is a 4096-bit number. The
reason that the number is so big, is that it is randomly generated
from a special algorithm that Microsoft invented -- the odds of it
conflicting with another PUID anywhere in the world are astronomically
unlikely, and the odds of that other PUID being linked into the same
program are virtually impossible. However, programmers that are
concerned about this possibility can give each PUID a password
(1-512 bytes, case-sensitive, non-printable bytes ARE permitted).
The syntax of these passwords have not yet been determined.

To simplify the system, these PUIDs are stored offline between
compilations in a PDB (PUID Database).

The programmer (or librarian) can also designate groups of PUIDs
as GUIDs (Group Unique Identification). It's easy to tell a PUID
from a GUID -- PUIDs always start with 0x01 and GUIDs always
start with 0x05. Other starting bytes are reserved for future use.
These too are stored in the PDB.

Finally, each object can have an ACL (Access Control List). This
is a list of PUIDs or GUIDs, along with an access level. I don't
fully understand access levels yet, but I'm told that almost all
of them will be one of four codes: None, Read, Write, Full. The
others involve passwords, current states, and time-of-day, but
I don't understand the details well enough to write about them.

Whenever one thing (the "Accessor") tries to access another (the
"Accessee"), the accessee's ACL is examined. If it contains the
PUID of the Accessor, the access check is made. Otherwise, the
accessor's groups are checked one at a time, in the order declared.
If none of the accessor's groups is found, then the "default access
level" is used.

Once the access level is found, an access/deny decision is made
based on current states, current time of day, the password if any,
and so on as specified in the ACL.

It is hoped that at least 90% of these access checks can be performed
at compile time, because runtime access checks can slow an application.
Fortunately this all depends on the access type; good applications
minimize the use of runtime access types.

Oh, and I forgot to mention the use of SPUIDs ("Super" PUIDs). These
are intended for compilers and debuggers, and are normally disabled
in production code. A special rule is that you have to look up
normal access first; if (and only if) access is denied, then the
system checks for SPUIDs. The reason for this is performance; it was
felt that checking for SPUIDs first would tend to IMPROVE performance
for SPUIDs, thus giving the programmer an incentive to use them.
We would prefer to discourage their use, but improved performance would
have the opposite effect -- thus the rule.



I was going to post a code snippet here, showing the pre-beta syntax
and demonstrating the benefits of the entire ACL system. However, I
decided to compile it first, to make sure I typed it correctly. If
there are no syntax errors, I should be able to post the code as
soon as the compiler finishes -- perhaps next Saturday.



For the cynics among you, who are looking for the smiley:   8^]>

---
[ 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: brangdon@cix.co.uk (Dave Harris)
Date: Fri, 24 Jan 2003 14:41:05 +0000 (UTC)
Raw View
ndenville@jands.com.au ("Nick Denville") wrote (abridged):
> I often find that it would be highly desirable to expose
> only a subset of a class's non-public members to a
> nominated class. I dislike using 'friend' for this purpose
> because it doesn't allow any selectivity as to what gets
> exposed, unlike using 'protected' to selectively expose
> to a derived class. I would like to propose the addition
> of the 'aquaintance' keyword to complement 'friend', which
> would allow access to the protected members

On the syntax side, I'd consider using some combination of existing
keywords for this. Eg:

     class Something {
         protected friend class Trusted;
         // ...
     };

So that plain "friend" would be equivalent to "private friend".

We can already achieve selective publishing by using various idioms - I'll
show one below. The part of your idea which interests me is that the
features available to the "friend" should match the ones available to
subclasses. In some ways that makes sense. Since that stuff is already
available to any number of subclasses, it won't hurt much to make it
available to friends also. Indeed, that seems so logical I wonder if we
should make protected friendship inheritable.

On the other hand, in the few cases I've been tempted to use "friend" the
needs of the friend didn't match the needs of subclasses at all. So maybe
it is not a good idea.

Anyway, here is another inheritance idiom (which at the time of posting is
different to those already here).

    class Trusting {
        class FriendInterface;
        friend class FriendInterface;
        int data;
        // ...
    };

    class Trusting::FriendInterface {
    protected:
        int GetData( const Trusting &t ) const {
            return t.data;
        }
        SetData( Trusting &t, int d ) {
            t.data = d;
        }
    };

    class Trusted : private Trusting::FriendInterface {
        void use( Trusting &t ) {
            // int data = t.data;
            int data = GetData( t );
        }
    };

This should have no run-time overhead, if the compiler is good. It allows
us to specify exactly what Trusted can do, by putting appropriate
functions into FriendInterface. It also allows unlimited Trusted-like
classes. This may be a good thing, because it reduces the coupling between
Trusted and Trusting (which is what makes "friend" controversial). It is
unlikely to be broken by accident, in that people are unlikely to inherit
from Trusting::FriendInterface unless that is what they really want.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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: llewelly.@@xmission.dot.com (llewelly)
Date: Fri, 24 Jan 2003 19:22:51 +0000 (UTC)
Raw View
acappellaguy@hotmail.com (A Cappella Guy) writes:

> In article <b0pskh$o9p$1@merki.connect.com.au>, Nick Denville
> <ndenville@jands.com.au> wrote:
> > To be honest, I wasn't aware that such a technique would work - it seems
> > that this would allow someone to break privacy of a class (at least to the
> > protected level) without the consent of that class (presuming this is what
> > you meant?):
>
> Well yeah.  In a sense, you could interpret "protected" to mean "you
> may use these if it's worth enough to you to bother subclassing me."
> For that matter, you can use private methods a la:
>
> class Foo {
>    void privateMethod();
> };
>
> struct Evil {
>    void privateMethod();
> };
>
> int main() {
>    Foo* foo = new Foo;
>    Evil* evil = reinterpret_cast<Evil*>foo;
>    evil->privateMethod();
> }
[snip]
Of course this works with most implementations, but it is undefined.

---
[ 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: jrl@utas.edu.au (James Doc Livingston)
Date: Sat, 25 Jan 2003 03:16:26 +0000 (UTC)
Raw View
ndenville@jands.com.au ("Nick Denville") wrote:
> I often find that it would be highly desirable to expose only a subset of a
> class's non-public members to a nominated class. I dislike using 'friend'
> for this purpose because it doesn't allow any selectivity as to what gets
> exposed, unlike using 'protected' to selectively expose to a derived class.

Personally I think that a better way to do this would be:

class Foo
{
public:
    void a();
private:
    friend class Bar, baz(int)
    {
        void b();
    }
}

So b() only gets exposed to the Bar class, and the baz(int) function.
This would allow you to specify exactly what you want exposed, and to
who. I don't think this could break any existing code, as this kind of
thing isn't legal. Also this method of doing it doesn't introduce any
new keywords.

Does anyone have any ideas on this method?

----
James "Doc" Livingston
jrl@utas.edu.au

---
[ 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: danielgutson@hotmail.com (danielgutson@hotmail.com)
Date: Sat, 25 Jan 2003 21:00:49 +0000 (UTC)
Raw View
ndenville@jands.com.au ("Nick Denville") wrote in message news:<b0pust$pt9$1@merki.connect.com.au>...
> <danielgutson@hotmail.com> wrote in message
> news:23478c42.0301231510.1e9e7ee1@posting.google.com...
> > there is no need of using friendship relations.
> > You can control accessibility by using interfaces and implemented them
> > in your class.
>
> That's an interesting alternative approach, but I think it does carry with
> it some inherent problems that may be inconvenient or even unacceptable in
> some cases.

Ok. Let's go by steps.
First, the classification of 'public, protected, private' is
accessibility in terms of INHERITANCE.
You are mixing accessibility with classes that don't belong to the
hierarchy graph, let's say 'outer classes'.
If you want to provide another accessibility criteria -not in terms of
inheritance- then you need an independent classification. I don't see
a reason by 'outer' classes might see just 'protected', instead of a
subset of public and protected (not all of them), or a subset of
protected and private.

For being graphic, let me call this different 'accessibility levels'
on criterions:
  INHERITANCE accessibility level: public (1), protected (2), private
(3)
  CUSTOM1 accssessibility level: true (1), false (0), ...
  CUSTOM2 acc. lvl. : ...
  ...
  CUSTOMn

So, we should be able to classify each method with a list of
accessibility levels of length n+1 (INHERITANCE plus the custom
criterions).

A good reason I'm saying this is because with accessibility levels
(existent or not) allows your class to ignore from its users, so you
can keep some good uncoupling level.
But idioms like 'friend' forces to tight the class to the user
classes, what is no good in terms of dependencies (more users you
create, more friendship relations you must add and therefore modify
the class). It has no natural extendibility.

[fiction]
What I suggest for achieving this, could be logical groupings of
classes, kind of 'clans' (Am I touching the 'package' concept of
java?).
If a class belongs to a clan, a criteria could be 'accessible by
members of the same clan'. And the class would ignore her clan
co-members (her brotherhood).
Clans could be nested in sub-clans, and this criteria would apply.

Then, you could get parallel accessibility levels: INHERITANCE, and
CLAN.

Perhaps my CLAN concept could be mapped to a namespace: they can be
nested, and we could differentiate:
    - raw public
    - visible by same clan|namespace members (and nested),
combinated with
    - public
    - private
    - protected

Then, a possible syntax would combine both inheritance access keywords
with the 'namespace' keyword, related with the || or && operator as
set operations:

public:
protected || namespace:
namespace:
protected && namespace:
private || namespace:
private:
private && namespace:

For example:
namespace X{
  class AClass
  {
   public:
       int x1;
   namespace:
       int x2;
   protected && namespace:
       int x3;
};

(as excersize, public && namespace == namespace; public || namespace
== public).

     Daniel.

---
[ 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: ndenville@jands.com.au ("Nick Denville")
Date: Thu, 23 Jan 2003 19:11:30 +0000 (UTC)
Raw View
Friends,

I often find that it would be highly desirable to expose only a subset of a
class's non-public members to a nominated class. I dislike using 'friend'
for this purpose because it doesn't allow any selectivity as to what gets
exposed, unlike using 'protected' to selectively expose to a derived class.
I would like to propose the addition of the 'aquaintance' keyword to
complement 'friend', which would allow access to the protected members,
e.g.:

class Something
{
    friend class Risky; // give access to all of my stuff to Risky class
    aquaintance class Trusted; // give access to only my protected members
to Trusted class
    public:
        Something();
    protected:
        void doSomethingSpecial();
    private:
        void forInternalUseOnly();
};

Thanks,

Nick


---
[ 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: acappellaguy@hotmail.com (A Cappella Guy)
Date: Thu, 23 Jan 2003 22:42:04 +0000 (UTC)
Raw View
In article <b0o2il$kio$1@merki.connect.com.au>, Nick Denville
<ndenville@jands.com.au> wrote:
> I often find that it would be highly desirable to expose only a subset of a
> class's non-public members to a nominated class. I dislike using 'friend'
> for this purpose because it doesn't allow any selectivity as to what gets
> exposed, unlike using 'protected' to selectively expose to a derived class.
> I would like to propose the addition of the 'aquaintance' keyword to
> complement 'friend', which would allow access to the protected members,

I'm not sure that overloading the protected keyword is the best way to
go about this.  I'm sure I could come up with an example of a class
that intends an entirely different subset of functionality to be
exposed to subclasses and acquaintances*.

What you want can be accomplished now via inheritance:

class Foo {
protected:
   void something();
};

class Acquaintance;
class Introducer : public Foo {
   friend class Acquaintance;
};

class Acquaintance {
   // Has access to protected members of Foo via Introducer
}

 -- A Cappella Guy

* - Note the spelling.  Acquaintance is not the easiest word in the
language to spell.  And though I'm sure most C++ users would quickly
learn the proper spelling, it's less wieldy than "guest" or something
shorter.

---
[ 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: Ken@Alverson.net ("Ken Alverson")
Date: Thu, 23 Jan 2003 23:22:06 +0000 (UTC)
Raw View
"A Cappella Guy" <acappellaguy@hotmail.com> wrote in message
news:230120031437186599%acappellaguy@hotmail.com...
>
> * - Note the spelling.  Acquaintance is not the easiest word in the
> language to spell.  And though I'm sure most C++ users would quickly
> learn the proper spelling, it's less wieldy than "guest" or something
> shorter.

For the very same reason, it's less likely to be an existing identifier
that would cause problems with the proposed keyword.

Whether or not that makes it a good choice, I don't know.

Ken


---
[ 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: ndenville@jands.com.au ("Nick Denville")
Date: Thu, 23 Jan 2003 23:22:14 +0000 (UTC)
Raw View
"A Cappella Guy" <acappellaguy@hotmail.com> wrote in message
news:230120031437186599%acappellaguy@hotmail.com...
> In article <b0o2il$kio$1@merki.connect.com.au>, Nick Denville
> <ndenville@jands.com.au> wrote:
> > I often find that it would be highly desirable to expose only a subset
of a
> > class's non-public members to a nominated class. I dislike using
'friend'
<snip>
>
> I'm not sure that overloading the protected keyword is the best way to
> go about this.  I'm sure I could come up with an example of a class
> that intends an entirely different subset of functionality to be
> exposed to subclasses and acquaintances*.
>
> What you want can be accomplished now via inheritance:
>
<snip>

Thanks for your reply. I agree that the proposed solution is not as flexible
as some may desire, but it does, however, afford much more flexibility than
using 'friend'.

I was prompted to suggest this to the group when considering a somewhat
'component-centric' design decomposition. The design in question involves a
group of classes that each encapsulate a portion of the implementation of an
enclosing class, and are entitled access to parts of the implementation of
that class. I'm not sure that an inheritance-based solution would do the
trick for me, and in any case it is less wieldy than simply using 'friend'.

To be honest, I wasn't aware that such a technique would work - it seems
that this would allow someone to break privacy of a class (at least to the
protected level) without the consent of that class (presuming this is what
you meant?):

class Something
{
public:
    Something(): _x(5) {}
protected:
    int x() {return _x;}
private:
    int _x;
};

class Introducer: public Something
{
    friend class Guest;
};

class Guest
{
public:
    void accessSomething(Something& s);
};

void Guest::accessSomething(Something& s)
{
    ((Introducer&)s).x();
}

I'd also agree that 'acquaintance' is pretty unwieldy and perhaps a little
flippant - 'guest' is a much better choice of keyword.



---
[ 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: danielgutson@hotmail.com (danielgutson@hotmail.com)
Date: Thu, 23 Jan 2003 23:22:25 +0000 (UTC)
Raw View
ndenville@jands.com.au ("Nick Denville") wrote in message news:<b0o2il$kio$1@merki.connect.com.au>...
> Friends,
>
> I often find that it would be highly desirable to expose only a subset of a
> class's non-public members to a nominated class. I dislike using 'friend'

there is no need of using friendship relations.
You can control accessibility by using interfaces and implemented them
in your class.

First complexity level example:

struct InterfaceForClass1
{
  virtual void method1()=0;
};

struct InterfaceForClass2
{
  virtual void method2()=0;
};

class YourClass : public InterfaceForClass1, public InterfaceForClass2
{
  virtual void method1() { ... }
  virtual void method1() {...}

};

class Class1
{
   public: void useInterface1(InterfaceForClass1* i1);
};

class Class2
{
   public: void useInterface2(InterfaceForClass2* i1);
};

---
Second complexity level example:
in the 'first level' complexity example, you might complain that, as
far as the inheritance is 'public', it would be a matter of honesty
from Class1 or Class2 to use the proper interface.
If you don't trust in them, you still can use private inheritance of
the classes. You will have to work a little more on this:

[InterfaceForClass1, InterfaceForClass2: unchanged from example above]
[Class1, Class2: unchanged too]

class YourClass : private InterfaceForClass1, private
InterfaceForClass2
{
  virtual void method1() { ... }
  virtual void method1() {...}

public:
  void beUsedByClass1(Class1& c1)
  {
     c1.useInterface1(this);
  }

  void beUsedByClass2(Class2& c1)
  {
     c1.useInterface2(this);
  }
};

Here, coupling level is sacrified in terms of 'safety'.
It's a matter of design.

   Daniel.

---
[ 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: ndenville@jands.com.au ("Nick Denville")
Date: Thu, 23 Jan 2003 23:50:38 +0000 (UTC)
Raw View
<danielgutson@hotmail.com> wrote in message
news:23478c42.0301231510.1e9e7ee1@posting.google.com...
> there is no need of using friendship relations.
> You can control accessibility by using interfaces and implemented them
> in your class.

That's an interesting alternative approach, but I think it does carry with
it some inherent problems that may be inconvenient or even unacceptable in
some cases.

Firstly, it mandates the use of polymorphism, which may have a
performance/size impact in some applications (especially deeply
embedded/real-time).

Secondly, it is non-trivial to employ: use of the 'protected' keyword is
very simple and straightforward means of controlling access from a derived
class; 'friend' is equally simple & straightforward at selecting which
unrelated classes are given higher 'privilege'. IMO there should be an
equally simple and straightforward solution to controlling access from these
selected privileged classes.

Thanks,

Nick


---
[ 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: llewelly.@@xmission.dot.com (llewelly)
Date: Fri, 24 Jan 2003 03:25:52 +0000 (UTC)
Raw View
acappellaguy@hotmail.com (A Cappella Guy) writes:
[snip]
> * - Note the spelling.  Acquaintance is not the easiest word in the
> language to spell.  And though I'm sure most C++ users would quickly
> learn the proper spelling, it's less wieldy than "guest" or something
> shorter.
[snip]

I don't see a great need for the 'acquaintance' feature, but I think
    the difficulty of spelling acquaintance is a good thing, if it is
    to be a new reserved word. It's unwieldiness means it will have
    been used as an identifier much less often.

---
[ 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: acappellaguy@hotmail.com (A Cappella Guy)
Date: Fri, 24 Jan 2003 03:46:16 +0000 (UTC)
Raw View
In article <b0pskh$o9p$1@merki.connect.com.au>, Nick Denville
<ndenville@jands.com.au> wrote:
> To be honest, I wasn't aware that such a technique would work - it seems
> that this would allow someone to break privacy of a class (at least to the
> protected level) without the consent of that class (presuming this is what
> you meant?):

Well yeah.  In a sense, you could interpret "protected" to mean "you
may use these if it's worth enough to you to bother subclassing me."
For that matter, you can use private methods a la:

class Foo {
   void privateMethod();
};

struct Evil {
   void privateMethod();
};

int main() {
   Foo* foo = new Foo;
   Evil* evil = reinterpret_cast<Evil*>foo;
   evil->privateMethod();
}

It boils down to varying degrees of willingness to break the intention
of the code you are accessing.  In the end, it's all just bits.  If the
language disallows something, asm will get to it.  I agree something
like your solution would offer a way for a component to publicize its
intentions more clearly so that such workarounds are less necessary.

 -- A Cappella Guy

---
[ 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                       ]