Topic: Improving Friends with Attributes
Author: martongabesz@gmail.com
Date: Fri, 18 May 2018 02:52:27 -0700 (PDT)
Raw View
------=_Part_9755_1246730338.1526637147725
Content-Type: multipart/alternative;
boundary="----=_Part_9756_1318495266.1526637147725"
------=_Part_9756_1318495266.1526637147725
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Hi,
The purpose of this mail is to provide an initial brief description of the=
=20
idea and to gauge the level of interest.
*) Introduction
The friend language construct is one of the oldest element in C++ and often=
=20
criticised.
Some people claim that friendship breaks the encapsulation, reflects bad=20
design and creates too strong coupling, thus they advise to avoid it.
However, friends appear even in the most carefully designed systems, and if=
=20
they are used judiciously they may be a better choice than widening the=20
public interface of a class.
Please see our research paper for details=20
(http://gsd.web.elte.hu/papers/2018/selective-friends_spe_2018.pdf).
*) Selective Friends
Empirical studies show that friend functions (and especially friend=20
classes) use only a low percentage of the private members they were granted=
=20
to have access to [1, 2].
Meyers states the encapsulation is greater if the number of functions that=
=20
can access the private parts of the class is fewer [3, Item 23].
Similarly, we state that the encapsulation is greater if the number of=20
accessible private entities is fewer because in that case the accessible=20
private part of the class is smaller.
We propose a new attribute [[selective_access]] that indicates that the=20
attributed friend is intended to access only a certain list of data=20
members, member functions or nested types of the befriending class.
If the given friend accesses other private or protected entities than those=
=20
listed by the attribute, the compiler is encouraged to issue a warning.
Example:
class A {
int x =3D 0;
int y =3D 0; // expected-note
// {{implicitly declared private here}}
friend void func(A &a) [[selective_access(x)]]; // expected-note
// {{ access=20
restricted to certain members }}
};
void func(A &a) {
a.x =3D 1; // OK
a.y =3D 1; // expected-warning
// {{'y' is a private member of 'A'}}
}
A proof-of-concept implementation is publicly available at=20
https://github.com/martong/clang/tree/selective_friend .
C++17 compliant compilers are required to silently ignore unknown=20
attributes, thus tools which do not support the new attribute would just=20
simply ignore it.
Supporting compilers can provide better diagnostics and warn the user.
By realizing this feature as an attribute, backward compatibility is=20
guaranteed and no syntax change is needed in the grammar.
Note, there has been a previous proposal with a bit similar semantics, but=
=20
with a very different syntax [4].
Alternatives:
- The Access Key Idiom [8, 9]. The drawback of this pattern is that we=20
cannot handle the accessing of member fields with it, we can handle only=20
member functions.
- The Attorney-Client Idiom [10]. The use of this idiom does not scale=20
well, because we would need to define several attorney classes if we wanted=
=20
to provide access for the different combination of members. Also, using too=
=20
many attorneys might result in unmaintainable and hardly understandable=20
code.
Other languages;
- The Eiffel programming language uses a special tagging mechanism for=20
every class member to achieve selective friend like access control. For=20
each member we may provide a list of classes which can have access to the=
=20
member.
*) Const Friends
Const correctness prevents us from inadvertently modifying something we=20
didn't expect would be modified.
There are certain cases when a friend function accesses the private or=20
protected members only in a read-only manner.
For instance, a friend stream output operator (<<) to dump the content of a=
=20
class does not modify the state of the class.
If that function was a member function then we would make that a const=20
member function.
This could be especially important in case of friend classes.
We propose a new attribute [[const_access]] that indicates that the=20
attributed friend is intended to have read-only access.
If the given friend accesses private or protected entities as lvalues, the=
=20
compiler is encouraged to issue a warning.
Example:
class A {
int x =3D 0;
int y =3D 0;
friend [[const_access]] class B; // read-only
};
class B {
void func(A &a) { // expected-warning, B has const access only
int i =3D a.x;
a.x =3D 1; // or expected-warning here
}
}
By realizing this feature as an attribute, backward compatibility is=20
guaranteed and no syntax change is needed in the grammar.
Friend is an explicit mechanism for granting access, just like membership.
Member functions and friend functions are equally privileged, they access=
=20
every innards of a class.
The major difference is that a friend function is called like f(x), while a=
=20
member function is called like x.f() [5, 6].
Stroustrup states that during the language design, a friendship declaration=
=20
was seen as a mechanism similar to that of one protection domain granting a=
=20
read-write capability to another.
It is an explicit and specific part of a class declaration [7, 2.10].
Thus, we conclude if there are const member functions then there should be=
=20
const friends as well.
We consider this argument so strong that alternatively to the attribute=20
syntax we propose to introduce a syntax change in the core language and=20
enable the possibility to declare a friend as const.
Example:
class A {
int x =3D 0;
int y =3D 0;
friend class B const; // read-only
};
*) Out-of-class Friends
White-box testing is a method of testing software that tests internal=20
structures or workings of an application.
This kind of testing requires accessing the internals of a class, thus the=
=20
friend language element is an appropriate tool to provide access for these=
=20
tests.
People often declare a test accessor class in the unit under test:
Class A {
friend class TestAccessor;
// ...
}
However, often we cannot modify or do not want to modify the original class=
=20
to inject a friend declaration just because of testing.
We propose a new attribute [[friend_for]] that indicates that the=20
attributed free function has access to the specified class private or=20
protected entities.
Compiler vendors should be encouraged to disable this attribute by default=
=20
so users should explicitly require this feature and they should use it only=
=20
for the purpose of white-box testing but not in production code.
Example:
class A {
int a =3D 0;
};
[[friend_for(A)]] void func(A &a) {
a.a =3D 1;
}
A proof-of-concept implementation is publicly available at=20
https://github.com/martong/clang/tree/out-of-class_friend_attr
Alternatives to out-of-class friends:
- #define public private (and #define class struct). The standard=20
explicitly prohibit this, people still do it.
- Exploit explicit template instantiation to gain access=20
(https://github.com/martong/access_private). Besides of being a verbose=20
solution, some compilers do not implement the relevant part of the=20
standard, thus this works only with GCC.
Other languages:
- Java package private
*) Combined attributes
The above attributes may be used not just individually, but combined.
Example:
class A {
int x =3D 0;
int y =3D 0;
friend [[const_access]][[selective_access(x)]] class B; // read-only=
=20
access of x only
};
Sincerely,
Gabor Marton
[1] English M,Buckley J,Cahill T.A friend in need is a friend indeed=20
[software metrics and friend functions].Empirical Software Engineering,=20
2005. 2005 International Symposium on, IEEE, 2005; 10=E2=80=93pp.
[2] M=C3=A1rton G, Porkol=C3=A1b Z. Selective friends in C++. Softw Pract E=
xper.=20
2018;1=E2=80=9327.
[3] Meyers S. Effective C++: 55 Specific Ways to Improve Your Programs and=
=20
Designs (3rdEdition). Addison-Wesley Professional, 2005. Item 46, p. 256.
[4] Refined friend,=20
https://groups.google.com/a/isocpp.org/forum/?fromgroups#!searchin/std-prop=
osals/friend/std-proposals/toC-ijCVBME/Ef5xJ54o4O4J
[5] isocpp org. C++ FAQ, Friends 2016. URL=20
https://isocpp.org/wiki/faq/friends, accessed: 2016-06-12.
[6] Stroustrup B. The C++ programming language. Pearson Education, 2013.
[7] Stroustrup B. The Design and Evolution of C++. ACM Press/Addison-Wesley=
=20
Publishing Co.: New York, NY, USA, 1994. P. 53.
[8]=20
https://stackoverflow.com/questions/3324248/how-to-name-this-key-oriented-a=
ccess-protection-pattern
[9]=20
http://talesofcpp.fusionfenix.com/post-4/episode-three-friends-with-benefit=
s
[10]=20
https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Friendship_and_the_Attorn=
ey-Client
--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/25e60cac-91d7-4197-9a08-ce8aa90e67ab%40isocpp.or=
g.
------=_Part_9756_1318495266.1526637147725
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><font face=3D"courier new, monospace">Hi,<br></font><=
/div><div><font face=3D"courier new, monospace"><br></font></div><div><font=
face=3D"courier new, monospace">The purpose of this mail is to provide an =
initial brief description of the idea and to gauge the level of interest.</=
font></div><div><font face=3D"courier new, monospace"><br></font></div><div=
><font face=3D"courier new, monospace"><br></font></div><div><font face=3D"=
courier new, monospace"><br></font></div><div><font face=3D"courier new, mo=
nospace">*) Introduction</font></div><div><font face=3D"courier new, monosp=
ace">The friend language construct is one of the oldest element in C++ and =
often criticised.</font></div><div><font face=3D"courier new, monospace">So=
me people claim that friendship breaks the encapsulation, reflects bad desi=
gn and creates too strong coupling, thus they advise to avoid it.</font></d=
iv><div><font face=3D"courier new, monospace">However, friends appear even =
in the most carefully designed systems, and if they are used judiciously th=
ey may be a better choice than widening the public interface of a class.</f=
ont></div><div><font face=3D"courier new, monospace">Please see our researc=
h paper for details (http://gsd.web.elte.hu/papers/2018/selective-friends_s=
pe_2018.pdf).</font></div><div><font face=3D"courier new, monospace"><br></=
font></div><div><font face=3D"courier new, monospace"><br></font></div><div=
><font face=3D"courier new, monospace"><br></font></div><div><font face=3D"=
courier new, monospace">*) Selective Friends</font></div><div><font face=3D=
"courier new, monospace">Empirical studies show that friend functions (and =
especially friend classes) use only a low percentage of the private members=
they were granted to have access to [1, 2].</font></div><div><font face=3D=
"courier new, monospace">Meyers states the encapsulation is greater if the =
number of functions that can access the private parts of the class is fewer=
[3, Item 23].</font></div><div><font face=3D"courier new, monospace">Simil=
arly, we state that the encapsulation is greater if the number of accessibl=
e private entities is fewer because in that case the accessible private par=
t of the class is smaller.</font></div><div><font face=3D"courier new, mono=
space">We propose a new attribute [[selective_access]] that indicates that =
the attributed friend is intended to access only a certain list of data mem=
bers, member functions or nested types of the befriending class.</font></di=
v><div><font face=3D"courier new, monospace">If the given friend accesses o=
ther private or protected entities than those listed by the attribute, the =
compiler is encouraged to issue a warning.</font></div><div><font face=3D"c=
ourier new, monospace">Example:</font></div><div><font face=3D"courier new,=
monospace">=C2=A0 =C2=A0 class A {</font></div><div><font face=3D"courier =
new, monospace">=C2=A0 =C2=A0 =C2=A0 int x =3D 0;</font></div><div><font fa=
ce=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 int y =3D 0; // expected=
-note</font></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// {{implicitly declared pr=
ivate here}}</font></div><div><font face=3D"courier new, monospace"><br></f=
ont></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 f=
riend void func(A &a) [[selective_access(x)]]; // expected-note</font><=
/div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 // {{ access restricted to certain members }}</font></div><di=
v><font face=3D"courier new, monospace">=C2=A0 =C2=A0 };</font></div><div><=
font face=3D"courier new, monospace">=C2=A0 =C2=A0 void func(A &a) {</f=
ont></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 a=
..x =3D 1; // OK</font></div><div><font face=3D"courier new, monospace">=C2=
=A0 =C2=A0 =C2=A0 a.y =3D 1; // expected-warning</font></div><div><font fac=
e=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0// {{'y' is a private member of 'A'}}</font></div=
><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 }</font></div><di=
v><font face=3D"courier new, monospace">A proof-of-concept implementation i=
s publicly available at https://github.com/martong/clang/tree/selective_fri=
end .</font></div><div><font face=3D"courier new, monospace"><br></font></d=
iv><div><font face=3D"courier new, monospace">C++17 compliant compilers are=
required to silently ignore unknown attributes, thus tools which do not su=
pport the new attribute would just simply ignore it.</font></div><div><font=
face=3D"courier new, monospace">Supporting compilers can provide better di=
agnostics and warn the user.</font></div><div><font face=3D"courier new, mo=
nospace">By realizing this feature as an attribute, backward compatibility =
is guaranteed and no syntax change is needed in the grammar.</font></div><d=
iv><font face=3D"courier new, monospace">Note, there has been a previous pr=
oposal with a bit similar semantics, but with a very different syntax [4].<=
/font></div><div><font face=3D"courier new, monospace"><br></font></div><di=
v><font face=3D"courier new, monospace">Alternatives:</font></div><div><fon=
t face=3D"courier new, monospace">- The Access Key Idiom [8, 9]. The drawba=
ck of this pattern is that we cannot handle the accessing of member fields =
with it, we can handle only member functions.</font></div><div><font face=
=3D"courier new, monospace">- The Attorney-Client Idiom [10]. The use of th=
is idiom does not scale well, because we would need to define several attor=
ney classes if we wanted to provide access for the different combination of=
members. Also, using too many attorneys might result in unmaintainable and=
hardly understandable code.</font></div><div><font face=3D"courier new, mo=
nospace"><br></font></div><div><font face=3D"courier new, monospace">Other =
languages;</font></div><div><font face=3D"courier new, monospace">- The Eif=
fel programming language uses a special tagging mechanism for every class m=
ember to achieve selective friend like access control. For each member we m=
ay provide a list of classes which can have access to the member.</font></d=
iv><div><font face=3D"courier new, monospace"><br></font></div><div><font f=
ace=3D"courier new, monospace"><br></font></div><div><font face=3D"courier =
new, monospace"><br></font></div><div><font face=3D"courier new, monospace"=
>*) Const Friends</font></div><div><font face=3D"courier new, monospace">Co=
nst correctness prevents us from inadvertently modifying something we didn&=
#39;t expect would be modified.</font></div><div><font face=3D"courier new,=
monospace">There are certain cases when a friend function accesses the pri=
vate or protected members only in a read-only manner.</font></div><div><fon=
t face=3D"courier new, monospace">For instance, a friend stream output oper=
ator (<<) to dump the content of a class does not modify the state of=
the class.</font></div><div><font face=3D"courier new, monospace">If that =
function was a member function then we would make that a const member funct=
ion.</font></div><div><font face=3D"courier new, monospace">This could be e=
specially important in case of friend classes.</font></div><div><font face=
=3D"courier new, monospace">We propose a new attribute [[const_access]] tha=
t indicates that the attributed friend is intended to have read-only access=
..</font></div><div><font face=3D"courier new, monospace">If the given frien=
d accesses private or protected entities as lvalues, the compiler is encour=
aged to issue a warning.</font></div><div><font face=3D"courier new, monosp=
ace">Example:</font></div><div><font face=3D"courier new, monospace">=C2=A0=
=C2=A0 class A {</font></div><div><font face=3D"courier new, monospace">=
=C2=A0 =C2=A0 =C2=A0 int x =3D 0;</font></div><div><font face=3D"courier ne=
w, monospace">=C2=A0 =C2=A0 =C2=A0 int y =3D 0;</font></div><div><font face=
=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 friend [[const_access]] cl=
ass B; // read-only</font></div><div><font face=3D"courier new, monospace">=
=C2=A0 =C2=A0 };</font></div><div><font face=3D"courier new, monospace">=C2=
=A0 =C2=A0 class B {</font></div><div><font face=3D"courier new, monospace"=
>=C2=A0 =C2=A0 =C2=A0 void func(A &a) { // expected-warning, B has cons=
t access only</font></div><div><font face=3D"courier new, monospace">=C2=A0=
=C2=A0 =C2=A0 =C2=A0 int i =3D a.x;</font></div><div><font face=3D"courier=
new, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 a.x =3D 1; // or expected-warn=
ing here</font></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=
=A0 =C2=A0 }</font></div><div><font face=3D"courier new, monospace">=C2=A0 =
=C2=A0 }</font></div><div><font face=3D"courier new, monospace">By realizin=
g this feature as an attribute, backward compatibility is guaranteed and no=
syntax change is needed in the grammar.</font></div><div><font face=3D"cou=
rier new, monospace"><br></font></div><div><font face=3D"courier new, monos=
pace">Friend is an explicit mechanism for granting access, just like member=
ship.</font></div><div><font face=3D"courier new, monospace">Member functio=
ns and friend functions are equally privileged, they access every innards o=
f a class.</font></div><div><font face=3D"courier new, monospace">The major=
difference is that a friend function is called like f(x), while a member f=
unction is called like x.f() [5, 6].</font></div><div><font face=3D"courier=
new, monospace">Stroustrup states that during the language design, a frien=
dship declaration was seen as a mechanism similar to that of one protection=
domain granting a read-write capability to another.</font></div><div><font=
face=3D"courier new, monospace">It is an explicit and specific part of a c=
lass declaration [7, 2.10].</font></div><div><font face=3D"courier new, mon=
ospace">Thus, we conclude if there are const member functions then there sh=
ould be const friends as well.</font></div><div><font face=3D"courier new, =
monospace">We consider this argument so strong that alternatively to the at=
tribute syntax we propose to introduce a syntax change in the core language=
and enable the possibility to declare a friend as const.</font></div><div>=
<font face=3D"courier new, monospace">Example:</font></div><div><font face=
=3D"courier new, monospace">=C2=A0 =C2=A0 class A {</font></div><div><font =
face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 int x =3D 0;</font></d=
iv><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 int y =
=3D 0;</font></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0=
=C2=A0 friend class B const; // read-only</font></div><div><font face=3D"c=
ourier new, monospace">=C2=A0 =C2=A0 };</font></div><div><font face=3D"cour=
ier new, monospace"><br></font></div><div><font face=3D"courier new, monosp=
ace"><br></font></div><div><font face=3D"courier new, monospace"><br></font=
></div><div><font face=3D"courier new, monospace">*) Out-of-class Friends</=
font></div><div><font face=3D"courier new, monospace">White-box testing is =
a method of testing software that tests internal structures or workings of =
an application.</font></div><div><font face=3D"courier new, monospace">This=
kind of testing requires accessing the internals of a class, thus the frie=
nd language element is an appropriate tool to provide access for these test=
s.</font></div><div><font face=3D"courier new, monospace">People often decl=
are a test accessor class in the unit under test:</font></div><div><font fa=
ce=3D"courier new, monospace">=C2=A0 =C2=A0 Class A {</font></div><div><fon=
t face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 friend class TestAcc=
essor;</font></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0=
=C2=A0 // ...</font></div><div><font face=3D"courier new, monospace">=C2=
=A0 =C2=A0 }</font></div><div><font face=3D"courier new, monospace">However=
, often we cannot modify or do not want to modify the original class to inj=
ect a friend declaration just because of testing.</font></div><div><font fa=
ce=3D"courier new, monospace">We propose a new attribute [[friend_for]] tha=
t indicates that the attributed free function has access to the specified c=
lass private or protected entities.</font></div><div><font face=3D"courier =
new, monospace">Compiler vendors should be encouraged to disable this attri=
bute by default so users should explicitly require this feature and they sh=
ould use it only for the purpose of white-box testing but not in production=
code.</font></div><div><font face=3D"courier new, monospace">Example:</fon=
t></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 class A {<=
/font></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0=
int a =3D 0;</font></div><div><font face=3D"courier new, monospace">=C2=A0=
=C2=A0 };</font></div><div><font face=3D"courier new, monospace">=C2=A0 =
=C2=A0 [[friend_for(A)]] void func(A &a) {</font></div><div><font face=
=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 a.a =3D 1;</font></div><di=
v><font face=3D"courier new, monospace">=C2=A0 =C2=A0 }</font></div><div><f=
ont face=3D"courier new, monospace">A proof-of-concept implementation is pu=
blicly available at https://github.com/martong/clang/tree/out-of-class_frie=
nd_attr</font></div><div><font face=3D"courier new, monospace"><br></font><=
/div><div><font face=3D"courier new, monospace">Alternatives to out-of-clas=
s friends:</font></div><div><font face=3D"courier new, monospace">- #define=
public private (and #define class struct). The standard explicitly prohibi=
t this, people still do it.</font></div><div><font face=3D"courier new, mon=
ospace">- Exploit explicit template instantiation to gain access (https://g=
ithub.com/martong/access_private). Besides of being a verbose solution, som=
e compilers do not implement the relevant part of the standard, thus this w=
orks only with GCC.</font></div><div><font face=3D"courier new, monospace">=
Other languages:</font></div><div><font face=3D"courier new, monospace">- J=
ava package private</font></div><div><font face=3D"courier new, monospace">=
<br></font></div><div><font face=3D"courier new, monospace"><br></font></di=
v><div><font face=3D"courier new, monospace"><br></font></div><div><font fa=
ce=3D"courier new, monospace">*) Combined attributes</font></div><div><font=
face=3D"courier new, monospace">The above attributes may be used not just =
individually, but combined.</font></div><div><font face=3D"courier new, mon=
ospace">Example:</font></div><div><font face=3D"courier new, monospace">=C2=
=A0 =C2=A0 class A {</font></div><div><font face=3D"courier new, monospace"=
>=C2=A0 =C2=A0 =C2=A0 int x =3D 0;</font></div><div><font face=3D"courier n=
ew, monospace">=C2=A0 =C2=A0 =C2=A0 int y =3D 0;</font></div><div><font fac=
e=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 friend [[const_access]][[=
selective_access(x)]] class B; // read-only access of x only</font></div><d=
iv><font face=3D"courier new, monospace">=C2=A0 =C2=A0 };</font></div><div>=
<font face=3D"courier new, monospace"><br></font></div><div><font face=3D"c=
ourier new, monospace"><br></font></div><div><font face=3D"courier new, mon=
ospace"><br></font></div><div><font face=3D"courier new, monospace">Sincere=
ly,</font></div><div><font face=3D"courier new, monospace">Gabor Marton</fo=
nt></div><div><font face=3D"courier new, monospace"><br></font></div><div><=
font face=3D"courier new, monospace"><br></font></div><div><font face=3D"co=
urier new, monospace"><br></font></div><div><font face=3D"courier new, mono=
space">[1] English M,Buckley J,Cahill T.A friend in need is a friend indeed=
[software metrics and friend functions].Empirical Software Engineering, 20=
05. 2005 International Symposium on, IEEE, 2005; 10=E2=80=93pp.</font></div=
><div><font face=3D"courier new, monospace">[2] M=C3=A1rton G, Porkol=C3=A1=
b Z. Selective friends in C++. Softw Pract Exper. 2018;1=E2=80=9327.</font>=
</div><div><font face=3D"courier new, monospace">[3] Meyers S. Effective C+=
+: 55 Specific Ways to Improve Your Programs and Designs (3rdEdition). Addi=
son-Wesley Professional, 2005. Item 46, p. 256.</font></div><div><font face=
=3D"courier new, monospace">[4] Refined friend, https://groups.google.com/a=
/isocpp.org/forum/?fromgroups#!searchin/std-proposals/friend/std-proposals/=
toC-ijCVBME/Ef5xJ54o4O4J</font></div><div><font face=3D"courier new, monosp=
ace">[5] isocpp org. C++ FAQ, Friends 2016. URL https://isocpp.org/wiki/faq=
/friends, accessed: 2016-06-12.</font></div><div><font face=3D"courier new,=
monospace">[6] Stroustrup B. The C++ programming language. Pearson Educati=
on, 2013.</font></div><div><font face=3D"courier new, monospace">[7] Strous=
trup B. The Design and Evolution of C++. ACM Press/Addison-Wesley Publishin=
g Co.: New York, NY, USA, 1994. P. 53.</font></div><div><font face=3D"couri=
er new, monospace">[8] https://stackoverflow.com/questions/3324248/how-to-n=
ame-this-key-oriented-access-protection-pattern</font></div><div><font face=
=3D"courier new, monospace">[9] http://talesofcpp.fusionfenix.com/post-4/ep=
isode-three-friends-with-benefits</font></div><div><font face=3D"courier ne=
w, monospace">[10] https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Friend=
ship_and_the_Attorney-Client</font></div><div><br></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/25e60cac-91d7-4197-9a08-ce8aa90e67ab%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/25e60cac-91d7-4197-9a08-ce8aa90e67ab=
%40isocpp.org</a>.<br />
------=_Part_9756_1318495266.1526637147725--
------=_Part_9755_1246730338.1526637147725--
.
Author: =?UTF-8?B?R8OhYm9yIE3DoXJ0b24=?= <martongabesz@gmail.com>
Date: Wed, 6 Mar 2019 11:04:36 +0100
Raw View
Ping
On Fri, May 18, 2018 at 11:52 AM <martongabesz@gmail.com> wrote:
>
> Hi,
>
> The purpose of this mail is to provide an initial brief description of th=
e idea and to gauge the level of interest.
>
>
>
> *) Introduction
> The friend language construct is one of the oldest element in C++ and oft=
en criticised.
> Some people claim that friendship breaks the encapsulation, reflects bad =
design and creates too strong coupling, thus they advise to avoid it.
> However, friends appear even in the most carefully designed systems, and =
if they are used judiciously they may be a better choice than widening the =
public interface of a class.
> Please see our research paper for details (http://gsd.web.elte.hu/papers/=
2018/selective-friends_spe_2018.pdf).
>
>
>
> *) Selective Friends
> Empirical studies show that friend functions (and especially friend class=
es) use only a low percentage of the private members they were granted to h=
ave access to [1, 2].
> Meyers states the encapsulation is greater if the number of functions tha=
t can access the private parts of the class is fewer [3, Item 23].
> Similarly, we state that the encapsulation is greater if the number of ac=
cessible private entities is fewer because in that case the accessible priv=
ate part of the class is smaller.
> We propose a new attribute [[selective_access]] that indicates that the a=
ttributed friend is intended to access only a certain list of data members,=
member functions or nested types of the befriending class.
> If the given friend accesses other private or protected entities than tho=
se listed by the attribute, the compiler is encouraged to issue a warning.
> Example:
> class A {
> int x =3D 0;
> int y =3D 0; // expected-note
> // {{implicitly declared private here}}
>
> friend void func(A &a) [[selective_access(x)]]; // expected-note
> // {{ access restri=
cted to certain members }}
> };
> void func(A &a) {
> a.x =3D 1; // OK
> a.y =3D 1; // expected-warning
> // {{'y' is a private member of 'A'}}
> }
> A proof-of-concept implementation is publicly available at https://github=
..com/martong/clang/tree/selective_friend .
>
> C++17 compliant compilers are required to silently ignore unknown attribu=
tes, thus tools which do not support the new attribute would just simply ig=
nore it.
> Supporting compilers can provide better diagnostics and warn the user.
> By realizing this feature as an attribute, backward compatibility is guar=
anteed and no syntax change is needed in the grammar.
> Note, there has been a previous proposal with a bit similar semantics, bu=
t with a very different syntax [4].
>
> Alternatives:
> - The Access Key Idiom [8, 9]. The drawback of this pattern is that we ca=
nnot handle the accessing of member fields with it, we can handle only memb=
er functions.
> - The Attorney-Client Idiom [10]. The use of this idiom does not scale we=
ll, because we would need to define several attorney classes if we wanted t=
o provide access for the different combination of members. Also, using too =
many attorneys might result in unmaintainable and hardly understandable cod=
e.
>
> Other languages;
> - The Eiffel programming language uses a special tagging mechanism for ev=
ery class member to achieve selective friend like access control. For each =
member we may provide a list of classes which can have access to the member=
..
>
>
>
> *) Const Friends
> Const correctness prevents us from inadvertently modifying something we d=
idn't expect would be modified.
> There are certain cases when a friend function accesses the private or pr=
otected members only in a read-only manner.
> For instance, a friend stream output operator (<<) to dump the content of=
a class does not modify the state of the class.
> If that function was a member function then we would make that a const me=
mber function.
> This could be especially important in case of friend classes.
> We propose a new attribute [[const_access]] that indicates that the attri=
buted friend is intended to have read-only access.
> If the given friend accesses private or protected entities as lvalues, th=
e compiler is encouraged to issue a warning.
> Example:
> class A {
> int x =3D 0;
> int y =3D 0;
> friend [[const_access]] class B; // read-only
> };
> class B {
> void func(A &a) { // expected-warning, B has const access only
> int i =3D a.x;
> a.x =3D 1; // or expected-warning here
> }
> }
> By realizing this feature as an attribute, backward compatibility is guar=
anteed and no syntax change is needed in the grammar.
>
> Friend is an explicit mechanism for granting access, just like membership=
..
> Member functions and friend functions are equally privileged, they access=
every innards of a class.
> The major difference is that a friend function is called like f(x), while=
a member function is called like x.f() [5, 6].
> Stroustrup states that during the language design, a friendship declarati=
on was seen as a mechanism similar to that of one protection domain grantin=
g a read-write capability to another.
> It is an explicit and specific part of a class declaration [7, 2.10].
> Thus, we conclude if there are const member functions then there should b=
e const friends as well.
> We consider this argument so strong that alternatively to the attribute s=
yntax we propose to introduce a syntax change in the core language and enab=
le the possibility to declare a friend as const.
> Example:
> class A {
> int x =3D 0;
> int y =3D 0;
> friend class B const; // read-only
> };
>
>
>
> *) Out-of-class Friends
> White-box testing is a method of testing software that tests internal str=
uctures or workings of an application.
> This kind of testing requires accessing the internals of a class, thus th=
e friend language element is an appropriate tool to provide access for thes=
e tests.
> People often declare a test accessor class in the unit under test:
> Class A {
> friend class TestAccessor;
> // ...
> }
> However, often we cannot modify or do not want to modify the original cla=
ss to inject a friend declaration just because of testing.
> We propose a new attribute [[friend_for]] that indicates that the attribu=
ted free function has access to the specified class private or protected en=
tities.
> Compiler vendors should be encouraged to disable this attribute by defaul=
t so users should explicitly require this feature and they should use it on=
ly for the purpose of white-box testing but not in production code.
> Example:
> class A {
> int a =3D 0;
> };
> [[friend_for(A)]] void func(A &a) {
> a.a =3D 1;
> }
> A proof-of-concept implementation is publicly available at https://github=
..com/martong/clang/tree/out-of-class_friend_attr
>
> Alternatives to out-of-class friends:
> - #define public private (and #define class struct). The standard explici=
tly prohibit this, people still do it.
> - Exploit explicit template instantiation to gain access (https://github.=
com/martong/access_private). Besides of being a verbose solution, some comp=
ilers do not implement the relevant part of the standard, thus this works o=
nly with GCC.
> Other languages:
> - Java package private
>
>
>
> *) Combined attributes
> The above attributes may be used not just individually, but combined.
> Example:
> class A {
> int x =3D 0;
> int y =3D 0;
> friend [[const_access]][[selective_access(x)]] class B; // read-onl=
y access of x only
> };
>
>
>
> Sincerely,
> Gabor Marton
>
>
>
> [1] English M,Buckley J,Cahill T.A friend in need is a friend indeed [sof=
tware metrics and friend functions].Empirical Software Engineering, 2005. 2=
005 International Symposium on, IEEE, 2005; 10=E2=80=93pp.
> [2] M=C3=A1rton G, Porkol=C3=A1b Z. Selective friends in C++. Softw Pract=
Exper. 2018;1=E2=80=9327.
> [3] Meyers S. Effective C++: 55 Specific Ways to Improve Your Programs an=
d Designs (3rdEdition). Addison-Wesley Professional, 2005. Item 46, p. 256.
> [4] Refined friend, https://groups.google.com/a/isocpp.org/forum/?fromgro=
ups#!searchin/std-proposals/friend/std-proposals/toC-ijCVBME/Ef5xJ54o4O4J
> [5] isocpp org. C++ FAQ, Friends 2016. URL https://isocpp.org/wiki/faq/fr=
iends, accessed: 2016-06-12.
> [6] Stroustrup B. The C++ programming language. Pearson Education, 2013.
> [7] Stroustrup B. The Design and Evolution of C++. ACM Press/Addison-Wesl=
ey Publishing Co.: New York, NY, USA, 1994. P. 53.
> [8] https://stackoverflow.com/questions/3324248/how-to-name-this-key-orie=
nted-access-protection-pattern
> [9] http://talesofcpp.fusionfenix.com/post-4/episode-three-friends-with-b=
enefits
> [10] https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Friendship_and_the=
_Attorney-Client
>
> --
> You received this message because you are subscribed to a topic in the Go=
ogle Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.=
org/d/topic/std-proposals/wtkDvujmjug/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to std-p=
roposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit https://groups.google.com/a/isoc=
pp.org/d/msgid/std-proposals/25e60cac-91d7-4197-9a08-ce8aa90e67ab%40isocpp.=
org.
--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CAH6rKyCTPMtUj8MPrB38K2rD-eGfEkoxeu%2B%2BJTKJMK-=
N-Pwj2w%40mail.gmail.com.
.
Author: Balog Pal <pasa@lib.hu>
Date: Mon, 18 Mar 2019 04:59:48 -0700 (PDT)
Raw View
------=_Part_292_1638369487.1552910388580
Content-Type: multipart/alternative;
boundary="----=_Part_293_1098072249.1552910388580"
------=_Part_293_1098072249.1552910388580
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
2018. m=C3=A1jus 18., p=C3=A9ntek 11:52:27 UTC+2 id=C5=91pontban marton...@=
gmail.com a=20
k=C3=B6vetkez=C5=91t =C3=ADrta:
>
> Example:
> class A {
> int x =3D 0;
> int y =3D 0; // expected-note
> // {{implicitly declared private here}}
>
> friend void func(A &a) [[selective_access(x)]]; // expected-note
> // {{ access=20
> restricted to certain members }}
> };
> void func(A &a) {
> a.x =3D 1; // OK
> a.y =3D 1; // expected-warning
> // {{'y' is a private member of 'A'}}
> }
>
>
I like the idea, and can confirm that I could use such extension in my=20
code. I agree with the statement that friend is a useful facility and that=
=20
most often we grant it for a single item or a small subset of the class.
OTOH the cases it cover are pretty rare and the extra protection is not=20
likely to catch a real problem. The reviews are sufficient for practice and=
=20
I can recall a strict zero accidents related to friend usage as we have it=
=20
now.
So this does not make it the "top 20" list of important issues maybe not=20
even the top 2000. IMHO spending the committee time on this is not=20
feasible. And would not be even without the massive backlog.
OTTH if you have the implementation, I suggest to make it an official pull=
=20
request in clang and gcc, it is fine as extension. A few years ahead it can=
=20
be pulled in the standard showing numbers of use.=20
=20
--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/144a411d-13a0-4348-a22c-05dbdf5ad952%40isocpp.or=
g.
------=_Part_293_1098072249.1552910388580
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>2018. m=C3=A1jus 18., p=C3=A9ntek 11:52:27 UTC+2 i=
d=C5=91pontban marton...@gmail.com a k=C3=B6vetkez=C5=91t =C3=ADrta:<blockq=
uote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-lef=
t: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><font face=3D"courie=
r new, monospace">Example:</font><div><font face=3D"courier new, monospace"=
>=C2=A0 =C2=A0 class A {</font></div><div><font face=3D"courier new, monosp=
ace">=C2=A0 =C2=A0 =C2=A0 int x =3D 0;</font></div><div><font face=3D"couri=
er new, monospace">=C2=A0 =C2=A0 =C2=A0 int y =3D 0; // expected-note</font=
></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0// {{implicitly declared private here=
}}</font></div><div><font face=3D"courier new, monospace"><br></font></div>=
<div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 friend void=
func(A &a) [[selective_access(x)]]; // expected-note</font></div><div>=
<font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 // {{ access restricted to certain members }}</font></div><div><font=
face=3D"courier new, monospace">=C2=A0 =C2=A0 };</font></div><div><font fa=
ce=3D"courier new, monospace">=C2=A0 =C2=A0 void func(A &a) {</font></d=
iv><div><font face=3D"courier new, monospace">=C2=A0 =C2=A0 =C2=A0 a.x =3D =
1; // OK</font></div><div><font face=3D"courier new, monospace">=C2=A0 =C2=
=A0 =C2=A0 a.y =3D 1; // expected-warning</font></div><div><font face=3D"co=
urier new, monospace">=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0// {{'y' is a private member of 'A'}}</font></div><div><=
font face=3D"courier new, monospace">=C2=A0 =C2=A0 }</font></div><br></div>=
</blockquote><div><br></div><div>I like the idea, and can confirm that I co=
uld use such extension in my code. I agree with the statement that friend i=
s a useful facility and that most often we grant it for a single item or a =
small subset of the class.</div><div><br></div><div>OTOH the cases it cover=
are pretty rare and the extra protection is not likely to catch a real pro=
blem. The reviews are sufficient for practice and I can recall a strict zer=
o accidents related to friend usage as we have it now.</div><div><br></div>=
<div>So this does not make it the "top 20" list of important issu=
es maybe not even the top 2000.=C2=A0=C2=A0 IMHO spending the committee tim=
e on this is not feasible. And would not be even without the massive backlo=
g.</div><div><br></div><div>OTTH if you have the implementation, I suggest =
to make it an official pull request in clang and gcc, it is fine as extensi=
on. A few years ahead it can be pulled in the standard showing numbers of u=
se. <br></div><div>=C2=A0</div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/144a411d-13a0-4348-a22c-05dbdf5ad952%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/144a411d-13a0-4348-a22c-05dbdf5ad952=
%40isocpp.org</a>.<br />
------=_Part_293_1098072249.1552910388580--
------=_Part_292_1638369487.1552910388580--
.