Topic: A proposal to add mutable function and mutable code section
Author: Hariharan Subramanian <tohari@gmail.com>
Date: Sat, 27 Apr 2013 07:02:57 -0700 (PDT)
Raw View
------=_Part_2388_22986614.1367071377261
Content-Type: text/plain; charset=ISO-8859-1
A proposal to add mutable function and mutable code section
*Problem:*
class Member; //definition elsewhere
class A
{
private:
Member *member;
//Other variables
public:
A() { member = nullptr; }
const Member* A::GetMember() const;
//Other functions
};
const Member* A::GetMember() const {
if(member == nullptr) {
//lazy initialize member
}
return member;
}
The above code results in compilation error as we modify a member variable
within a const function.
*Current solutions and their problems:*
*Current Solution 1:*
Make member variable mutable.
*The problem with this solution:*
This defeats the very purpose of having const member functions.
Semantically it is a constant and other const functions should not modify
it. Making it mutable gives any function the power to modify it. If there
are lot of lazy member initializations then all those member variables need
to be declared mutable and that makes the program error prone.
*Current Solution 2:*
Let the return value be const but the function be non-const. Hence the
prototype becomes const Member* A::GetMember().
*The problem with this solution:*
Consider the code below.
void foo(const A &obj) {
const Member &m1 = obj.GetMember(); //Compilation error!
}
To avoid the above compilation error const_cast the 'obj' or pass A &obj
instead of const A &obj. If we do a const_cast it would mean that all the
functions that have const A& should do a const_cast to call GetMember. This
results in a difficult to maintain code. The other alternative of passing A
&obj postpones the problem to the callee of foo. Now that callee function
has to make the same decision. This has the cascading effect.
*Proposed solution:*
We can see that none of the above solutions are desirable. We can introduce
the concept of mutable function and mutable code section.
*Solution using mutable code section:*
const Member* A::GetMember() const {
mutable {
if(member == nullptr) {
//lazy initialize member
}
}
return member;
}
The above mutable code section tells the compiler to suspend checking if
variables are modified or not.
*Solution using mutable function:*
Introduce a new private mutable member function LazyInitializeMember. The
code will be changed like this.
void A::LazyInitializeMember() mutable {
//lazy intialize member
}
const Member* A::GetMember() const {
LazyInitializeMember();
return member;
}
Even const member functions and const variables can call a mutable
function. A mutable function can call both const and non-const functions.
The above two solutions capture the intent of the programmer "Even though
this function modifies the member variable it is fine to treat it as a no
modification". Mutable function/code section makes the code less error
prone and easier to maintain. Mutable member variable has a different
intent "This variable can be modified by any function without affecting
const-ness". In fact mutable member variable and mutable function/code
section are complementary.
*Other points:*
1. Is there any real life use case for mutable public member functions?
They are as dangerous as mutable public member variables.
2a. Can we nest a mutable code section within a mutable code section even
though it is redundant?
2b. As we have mutable code section do we need to have const code section
also? In a const code section we cannot modify a member variable with the
exception of mutable member variable. We should also be able to nest a
mutable code section within a const code section and vice versa. This can
be taken to multiple levels.
mutable {
const {
mutable {
}
}
}
Even though it might seem that we should allow 2a if we allow 2b it is not
true. We can only disallow redundant code sections while allowing 2b.
3. Do we have to specify what member variables are mutable in the mutable
code section?
mutable (member) {
//Only 'member' can be modified. Other variables cannot be modified.
}
If we have const code section then it also should have this capability to
specify.
4. Do we disallow or let the compiler generate a warning if we don't modify
any member variable within a mutable code section/function. Point 3 should
be taken into consideration for this.
*Another example:*
http://www.geeksforgeeks.org/a-linked-list-with-next-and-arbit-pointer/
The link above has the problem definition (cloning a linked list) and 2
solutions. The first solution takes O(n) time and O(n) space. The second
solution takes O(n) time and O(1) space. If cloning is implemented using
the second solution the original linked list should be modified and
restored. Mutable function/code section is apt for this. Otherwise we need
to make the next pointer mutable which is incorrect or make the clone
function non-const which is also incorrect.
--
---
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 email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/?hl=en.
------=_Part_2388_22986614.1367071377261
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
<div><font size=3D"4">A proposal to add mutable function and mutable code s=
ection</font></div><div><br></div><div><b>Problem:</b></div><div><br></div>=
<div>class Member; //definition elsewhere</div><div><br></div><div>class A<=
/div><div>{</div><div>private:</div><div><span class=3D"Apple-tab-span" sty=
le=3D"white-space:pre"> </span>Member *member;</div><div><span class=3D"App=
le-tab-span" style=3D"white-space:pre"> </span>//Other variables</div><div>=
public:</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre">=
</span>A() { member =3D nullptr; }</div><div><span class=3D"Apple-tab-span=
" style=3D"white-space:pre"> </span>const Member* A::GetMember() const;</di=
v><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>//O=
ther functions</div><div>};</div><div><br></div><div>const Member* A::GetMe=
mber() const {</div><div><span class=3D"Apple-tab-span" style=3D"white-spac=
e:pre"> </span>if(member =3D=3D nullptr) {</div><div><span class=3D"Apple-t=
ab-span" style=3D"white-space:pre"> </span>//lazy initialize member</div><=
div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>}</div=
><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>retu=
rn member;</div><div>}</div><div><br></div><div>The above code results in c=
ompilation error as we modify a member variable within a const function.</d=
iv><div><br></div><div><b>Current solutions and their problems:</b></div><d=
iv><br></div><div><b>Current Solution 1:</b></div><div>Make member variable=
mutable.</div><div><b>The problem with this solution:</b></div><div>This d=
efeats the very purpose of having const member functions. Semantically it i=
s a constant and other const functions should not modify it. Making it muta=
ble gives any function the power to modify it. If there are lot of lazy mem=
ber initializations then all those member variables need to be declared mut=
able and that makes the program error prone.</div><div><br></div><div><b>Cu=
rrent Solution 2:</b></div><div>Let the return value be const but the funct=
ion be non-const. Hence the prototype becomes const Member* A::GetMember().=
</div><div><b>The problem with this solution:</b></div><div>Consider the co=
de below.</div><div>void foo(const A &obj) {</div><div><span class=3D"A=
pple-tab-span" style=3D"white-space:pre"> </span>const Member &m1 =3D o=
bj.GetMember(); //Compilation error!</div><div>}</div><div>To avoid the abo=
ve compilation error const_cast the 'obj' or pass A &obj instead of con=
st A &obj. If we do a const_cast it would mean that all the functions t=
hat have const A& should do a const_cast to call GetMember. This result=
s in a difficult to maintain code. The other alternative of passing A &=
obj postpones the problem to the callee of foo. Now that callee function ha=
s to make the same decision. This has the cascading effect.</div><div><br><=
/div><div><b>Proposed solution:</b></div><div>We can see that none of the a=
bove solutions are desirable. We can introduce the concept of mutable funct=
ion and mutable code section.</div><div><br></div><div><b>Solution using mu=
table code section:</b></div><div><br></div><div>const Member* A::GetMember=
() const {</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pr=
e"> </span>mutable {</div><div><span class=3D"Apple-tab-span" style=3D"whit=
e-space:pre"> </span>if(member =3D=3D nullptr) {</div><div><span class=3D"=
Apple-tab-span" style=3D"white-space:pre"> </span>//lazy initialize membe=
r</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </sp=
an>}</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </=
span>}</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> =
</span>return member;</div><div>}</div><div><br></div><div>The above mutabl=
e code section tells the compiler to suspend checking if variables are modi=
fied or not.</div><div><br></div><div><b>Solution using mutable function:</=
b></div><div>Introduce a new private mutable member function LazyInitialize=
Member. The code will be changed like this.</div><div><br></div><div>void A=
::LazyInitializeMember() mutable {</div><div><span class=3D"Apple-tab-span"=
style=3D"white-space:pre"> </span>//lazy intialize member</div><div>}</div=
><div><br></div><div>const Member* A::GetMember() const {</div><div><span c=
lass=3D"Apple-tab-span" style=3D"white-space:pre"> </span>LazyInitializeMem=
ber();</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> =
</span>return member;</div><div>}</div><div><br></div><div>Even const membe=
r functions and const variables can call a mutable function. A mutable func=
tion can call both const and non-const functions.</div><div><br></div><div>=
The above two solutions capture the intent of the programmer "Even though t=
his function modifies the member variable it is fine to treat it as a no mo=
dification". Mutable function/code section makes the code less error prone =
and easier to maintain. Mutable member variable has a different intent "Thi=
s variable can be modified by any function without affecting const-ness". I=
n fact mutable member variable and mutable function/code section are comple=
mentary.</div><div><br></div><div><b>Other points:</b></div><div>1. Is ther=
e any real life use case for mutable public member functions? They are as d=
angerous as mutable public member variables.</div><div>2a. Can we nest a mu=
table code section within a mutable code section even though it is redundan=
t?</div><div>2b. As we have mutable code section do we need to have const c=
ode section also? In a const code section we cannot modify a member variabl=
e with the exception of mutable member variable. We should also be able to =
nest a mutable code section within a const code section and vice versa. Thi=
s can be taken to multiple levels.</div><div>mutable {</div><div><span clas=
s=3D"Apple-tab-span" style=3D"white-space:pre"> </span>const {</div><div><s=
pan class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>mutable {</=
div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>=
}</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </spa=
n>}</div><div>}</div><div>Even though it might seem that we should allow 2a=
if we allow 2b it is not true. We can only disallow redundant code section=
s while allowing 2b.</div><div>3. Do we have to specify what member variabl=
es are mutable in the mutable code section?</div><div><br></div><div>mutabl=
e (member) {</div><div><span class=3D"Apple-tab-span" style=3D"white-space:=
pre"> </span>//Only 'member' can be modified. Other variables cannot be mod=
ified.</div><div>}</div><div>If we have const code section then it also sho=
uld have this capability to specify.</div><div>4. Do we disallow or let the=
compiler generate a warning if we don't modify any member variable within =
a mutable code section/function. Point 3 should be taken into consideration=
for this.</div><div><br></div><div><b>Another example:</b></div><div><a hr=
ef=3D"http://www.geeksforgeeks.org/a-linked-list-with-next-and-arbit-pointe=
r/">http://www.geeksforgeeks.org/a-linked-list-with-next-and-arbit-pointer/=
</a></div><div>The link above has the problem definition (cloning a linked =
list) and 2 solutions. The first solution takes O(n) time and O(n) space. T=
he second solution takes O(n) time and O(1) space. If cloning is implemente=
d using the second solution the original linked list should be modified and=
restored. Mutable function/code section is apt for this. Otherwise we need=
to make the next pointer mutable which is incorrect or make the clone func=
tion non-const which is also incorrect.</div><div><br></div>
<p></p>
-- <br />
<br />
--- <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 std-proposals+unsubscribe@isocpp.org.<br />
To post to this group, send email to std-proposals@isocpp.org.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/?hl=3Den">http://groups.google.com/a/isocpp.org/group/std-pro=
posals/?hl=3Den</a>.<br />
<br />
<br />
------=_Part_2388_22986614.1367071377261--
.