Topic: using const to signify an expectation of a function


Author: Till Heinzel <tillheinzel@hotmail.com>
Date: Sat, 27 Aug 2016 13:52:42 -0700 (PDT)
Raw View
------=_Part_1448_1836618934.1472331162059
Content-Type: multipart/alternative;
 boundary="----=_Part_1449_1363987102.1472331162060"

------=_Part_1449_1363987102.1472331162060
Content-Type: text/plain; charset=UTF-8


I suspect this to have been proposed in some form or other before, but I
couldn't find anything. It is also completely from a users perspective, as
I am not an expert on implementation details. This may also already be
possible in some form, in which case I apologize for my ignorance.

In short, I want to be able to classify a variable passed to a function as
const, without having to define it const:

void f(int){}


int main()
{
    int i = 0;
    f(const i); // requires the function signature of f to be such, that i
cannot be modified by it. So passed by value or const ref.
}

In this example it is pretty unnecessary, but it could be useful in certain
situations.
The idea is that the interface of the called function is more explicitly
specified by the caller, which could make it easier to find errors
introduced by a change in the interface of a function.

some cases:
1) The most useful situation I can think of is when calling dependent
functions within templates:

template<class T>
void f(T& t)
{
    X x{};
    auto y = t.g(x);
    ... do more stuff with x, y, t
}

In principle, it is unclear whether g modifies x or not. It could easily
take a reference and change x. We would have to depend on the name of the
function or check all possible T used with f to be certain.
So the modified line would be:

auto x = T.g(const x);


In this case it would implicitly constrain the possible types of T. It
would also not make x a constant, so it could still be modified in the rest
of the function.

2)  It could help specify overload resolution with forwarding references
(note: This may be a little artificial, I have not met the problem in code).

struct Z{};

void f(const Z& z);

template<class T> void f(T&& t){...}

int main()
{
    Z z1{};
const Z z2{};
f(z1); // calls template with T = Z&
f(z2); // calls f(const Z&)
// f(const z1) // would call f(const Z&)
}

In both cases the same could be achieved with a const& alias, but that
would be less easy to read and might introduce runtime overhead (possibly
extra pointers?).
I think it could also be achieved with metaprogramming or concepts.
Another alternative might be to use casts to const&, although that would
definitely impede readability. I'm also not completely certain about the
implementation of casts, but if it works like other function-calls, this
may create extra indirection through more pointers.


   - It would not introduce any new keywords, and it would not break any
   existing code, as const can already not be used for names.
   - It might decrease readability if used excessively.
   - However, it might also catch some errors. In general, it would be a
   way to document programmer intent in code, which would be checkable by a
   compiler. The alternative of using an alias might actually be a way to
   implement this, but then there might be runtime overhead. In principle,
   this should be a compile-time feature only.
   - I have not thought too much about pointers as I try to avoid raw ones,
   but I guess a const would imply "const* const" and a mutable the other
   extreme  of "*"


Going further, a similar feature might be useful for cases where we want to
specify a function to be expected to modify an object. This might again be
useful in template code, where we do not know the exact interface to the
called function. The keyword is a little less clear, but mutable might
work, also the best would be something like out, as in c#, but that would
introduce a new keyword. The implication would be that the function called
must be able to modify the object, which excludes pass by value or const&.

Another direction to go is to also allow the specifier on the function call
itself:

void f(T& t){
    t.const g();
}

which might again decrease readability but increase compile-time checks. As
const-correctness is supposed to relate to the external state of an object,
this would express, that we do not expect the behaviour of the object t to
be changed after this call.

Again something like mutable might be useful to specify when we expect a
mutator.

All in all, I see this as mostly useful in template-code, where the exact
signature of a called function might be unknown, and to increase compile
time checking of expected behaviour of functions.

--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/25f8ca3e-9d62-4fd9-a178-a7707425b315%40isocpp.org.

------=_Part_1449_1363987102.1472331162060
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div><br></div><div>I suspect this to have been proposed i=
n some form or other before, but I couldn&#39;t find anything. It is also c=
ompletely from a users perspective, as I am not an expert on implementation=
 details. This may also already be possible in some form, in which case I a=
pologize for my ignorance.</div><div><br></div><div>In short, I want to be =
able to classify a variable passed to a function as const, without having t=
o define it const:</div><div><br></div><div class=3D"prettyprint" style=3D"=
border: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-col=
or: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subprett=
yprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">void</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> f</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"=
color: #008;" class=3D"styled-by-prettify">int</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">){}</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"><br><br><br></span><span style=3D"color: #008;=
" class=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> main</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">()</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-pretti=
fy">int</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> i =
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span sty=
le=3D"color: #066;" class=3D"styled-by-prettify">0</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 f</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;=
" class=3D"styled-by-prettify">const</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> i</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">);</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> </span><span style=3D"color: #800;" class=3D"styled-by-prettify"=
>// requires the function signature of f to be such, that i cannot be modif=
ied by it. So passed by value or const ref.</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">}</span></div></code></div><div><br></div><div>I=
n this example it is pretty unnecessary, but it could be useful in certain =
situations.</div><div>The idea is that the interface of the called function=
 is more explicitly specified by the caller, which could make it easier to =
find errors introduced by a change in the interface of a function.</div><di=
v><br></div><div>some cases:</div><div>1) The most useful situation I can t=
hink of is when calling dependent functions within templates:</div><div><br=
></div><div class=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, =
187); word-wrap: break-word; background-color: rgb(250, 250, 250);"><code c=
lass=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">template</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">&lt;</span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">class</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> T</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">&gt;</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"><br></span><span style=3D"color: #008;" class=3D"styled-by-prettify"=
>void</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> f</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify">T</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">&amp;</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> t</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"><br>=C2=A0 =C2=A0 X x</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">{};</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">auto</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"> y </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> t</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify">g</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify">x</span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">...</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styl=
ed-by-prettify">do</span><span style=3D"color: #000;" class=3D"styled-by-pr=
ettify"> more stuff </span><span style=3D"color: #008;" class=3D"styled-by-=
prettify">with</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> x</span><span style=3D"color: #660;" class=3D"styled-by-prettify">,</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> y</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> t<br></span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">}</span></div></code></div><div>=
<br></div><div>In principle, it is unclear whether g modifies x or not. It =
could easily take a reference and change x. We would have to depend on the =
name of the function or check all possible T used with f to be certain.</di=
v><div>So the modified line would be:</div><div><br></div><div><div class=
=3D"prettyprint" style=3D"border: 1px solid rgb(187, 187, 187); word-wrap: =
break-word; background-color: rgb(250, 250, 250);"><code class=3D"prettypri=
nt"><div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">auto</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> x </span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> T<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify">g</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">const</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> x</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">);</span></div></code></div><br></div><div><br></d=
iv><div>In this case it would implicitly constrain the possible types of T.=
 It would also not make x a constant, so it could still be modified in the =
rest of the function.</div><div><br></div><div>2) =C2=A0It could help speci=
fy overload resolution with forwarding references (note: This may be a litt=
le artificial, I have not met the problem in code).</div><div><br></div><di=
v>struct Z{};</div><div><br></div><div>void f(const Z&amp; z);</div><div><b=
r></div><div>template&lt;class T&gt; void f(T&amp;&amp; t){...}</div><div><=
br></div><div>int main()</div><div>{</div><div>=C2=A0 =C2=A0 Z z1{};</div><=
div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>const =
Z z2{};</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>f(z1); // calls template with T =3D Z&amp;</div><div><span class=
=3D"Apple-tab-span" style=3D"white-space:pre"> </span>f(z2); // calls f(con=
st Z&amp;)</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pr=
e"> </span>// f(const z1) // would call f(const Z&amp;)</div><div>}</div><d=
iv><br></div><div>In both cases the same could be achieved with a const&amp=
; alias, but that would be less easy to read and might introduce runtime ov=
erhead (possibly extra pointers?).</div><div>I think it could also be achie=
ved with metaprogramming or concepts.</div><div>Another alternative might b=
e to use casts to const&amp;, although that would definitely impede readabi=
lity. I&#39;m also not completely certain about the implementation of casts=
, but if it works like other function-calls, this may create extra indirect=
ion through more pointers.</div><div><br></div><div><ul><li>It would not in=
troduce any new keywords, and it would not break any existing code, as cons=
t can already not be used for names.=C2=A0<br></li><li>It might decrease re=
adability if used excessively.=C2=A0<br></li><li>However, it might also cat=
ch some errors. In general, it would be a way to document programmer intent=
 in code, which would be checkable by a compiler. The alternative of using =
an alias might actually be a way to implement this, but then there might be=
 runtime overhead. In principle, this should be a compile-time feature only=
..<br></li><li><span style=3D"line-height: normal;">I have not thought too m=
uch about pointers as I try to avoid raw ones, but I guess a const would im=
ply &quot;const* const&quot; and a mutable the other extreme =C2=A0of &quot=
;*&quot;</span><br></li></ul></div><div><br></div><div>Going further, a sim=
ilar feature might be useful for cases where we want to specify a function =
to be expected to modify an object. This might again be useful in template =
code, where we do not know the exact interface to the called function. The =
keyword is a little less clear, but mutable might work, also the best would=
 be something like out, as in c#, but that would introduce a new keyword. T=
he implication would be that the function called must be able to modify the=
 object, which excludes pass by value or const&amp;.=C2=A0</div><div><br></=
div><div>Another direction to go is to also allow the specifier on the func=
tion call itself:</div><div><br></div><div class=3D"prettyprint" style=3D"b=
order: 1px solid rgb(187, 187, 187); word-wrap: break-word; background-colo=
r: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"subpretty=
print"><span style=3D"color: #008;" class=3D"styled-by-prettify">void</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> f</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">T</span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">&amp;</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> t</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">){</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"><br>=C2=A0 =C2=A0 t</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">.</span><span style=3D"color: #008;" class=3D"styled-b=
y-prettify">const</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> g</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(=
);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">}</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code=
></div><div><br></div><div>which might again decrease readability but incre=
ase compile-time checks. As const-correctness is supposed to relate to the =
external state of an object, this would express, that we do not expect the =
behaviour of the object t to be changed after this call.=C2=A0</div><div><b=
r></div><div>Again something like mutable might be useful to specify when w=
e expect a mutator.=C2=A0</div><div><br></div><div>All in all, I see this a=
s mostly useful in template-code, where the exact signature of a called fun=
ction might be unknown, and to increase compile time checking of expected b=
ehaviour of functions.</div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; 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/25f8ca3e-9d62-4fd9-a178-a7707425b315%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/25f8ca3e-9d62-4fd9-a178-a7707425b315=
%40isocpp.org</a>.<br />

------=_Part_1449_1363987102.1472331162060--

------=_Part_1448_1836618934.1472331162059--

.