Topic: Standardising statement expressions as a special kind


Author: Niall Douglas <nialldouglas14@gmail.com>
Date: Tue, 10 Oct 2017 16:02:48 -0700 (PDT)
Raw View
------=_Part_8524_716728600.1507676568868
Content-Type: multipart/alternative;
 boundary="----=_Part_8525_619870399.1507676568869"

------=_Part_8525_619870399.1507676568869
Content-Type: text/plain; charset="UTF-8"

In the process of preparing the operator try paper, I was hoping to gauge
just how much people hate the idea of adding statement expressions to C++?

Statement expressions are an extension provided by GCC and clang
(https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html) and take the form:

int a = ({
  int y = foo ();
  int z;
  if (y > 0)
    z = y;
  else z = - y;
  z;  // the output of the statement expression
});


A statement expression is executed directly inside its calling function. It
does NOT create a new stack frame, so this works:

int foo()
{
  return 1 + ({
    int a = boo();
    if(!a)
      return -1;  // returns from foo()
    a;
  });
}


So what I have in mind is even worse than this. I'm thinking of proposing
extending lambdas with some appalling new semantics:

int foo()
{
  return 1 + [!]{
    int a = boo();
    if(!a)
      return -1;  // returns from foo()
    a;
  }();
}

The new '!' capturing flag means "execute this in the stack frame of my
caller". Or rather, it means "execute this in *one* stack frame above this
lambda function's stack frame" because yes, you can do multiple '!':

void evil()
{
  // Inject "return 5;" into whomever calls evil()
  [!!] { return 5; }();
}


int foo()
{
  evil();  // as if "return 5;"
}

And you can also do '!!!' or '!!!!' and so on up to the current
inlineability limit of the code currently being compiled.

I am very sure most reading will hate this proposal, and I am making it
semi-seriously to see just how much people hate it before I describe it in
P0779R0. But what I would say in its favour is that it would solve the last
remaining major use case for C macros in C++: injecting boilerplate into a
caller's stack frame. And furthermore, I am unaware of *any other proposed
alternative* for injecting boilerplate into a caller's stack frame *other* than
C macros. Even Herb's metaclasses don't cover this use case as far as I
read them, which means we still will be using C macros to achieve
boilerplate injection in 2025.

And I don't know about you, but I'd like to see the back of C macros.

These "evil lambdas" would solve the problem. You basically get to alias a
function call to expand into some boilerplate, much tidier than C macro
expansion because it follows normal C++ rules, not the preprocessor's weird
rules. The availability of this facility would let one turn the Coroutines
TS into an almost entirely library based implementation for example. My
operator try idea is just injection of boilerplate as well, it becomes much
tidier with this facility in place. Ranged for loops again can be
implemented using these. Anywhere where we inject boilerplate, we can
inject these instead and make them library implemented, not hard coded into
the compiler.

But there are also lots, and lots of other awful unforeseen consequences.
Like you'd surely have to allow evil lambdas which inject programmatically
determined evil lambdas right? What kind of rabbit holes does that open up?
Evil lambdas can inject arbitrary new variables, modify existing ones,
change control flow, inject try and catch, basically do anything which C
macros can do, but without the problems associated with C macros. What
about ordering? Should injection of evil lambda contents occur in the order
of compilation? What if an evil lambda injects code three stack frames up
which transforms the evil lambda doing the injecting? It would be easiest
to just bail out, but it would be more *fun* if evil lambdas could
recursively rewrite themselves.

What do people think?

Niall

--
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/3beae118-eaad-485e-835c-ecb19d145098%40isocpp.org.

------=_Part_8525_619870399.1507676568869
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">In the process of preparing the operator try paper, I was =
hoping to gauge just how much people hate the idea of adding statement expr=
essions to C++?<div><br></div><div>Statement expressions are an extension p=
rovided by GCC and clang (https://gcc.gnu.org/onlinedocs/gcc/Statement-Expr=
s.html) and take the form:</div><div><br></div><div><pre class=3D"smallexam=
ple" style=3D"font-size: medium; background: rgb(242, 242, 249); padding: 4=
px; color: rgb(0, 0, 0);"><div class=3D"prettyprint" style=3D"background-co=
lor: rgb(250, 250, 250); border-color: rgb(187, 187, 187); border-style: so=
lid; border-width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"=
><div class=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled=
-by-prettify">int</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> a </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 style=3D"color: #660;" class=3D"styled-by-prettify">({</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">int</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> y </span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"> foo </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">();</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"><br>=C2=A0 </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> z</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
<br>=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify"=
>if</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">y </span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">&gt;</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" cl=
ass=3D"styled-by-prettify">0</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 z </span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"> y</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">;</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
=C2=A0 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">els=
e</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> z </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 style=3D"=
color: #660;" class=3D"styled-by-prettify">-</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> y</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"><br>=C2=A0 z</span><span style=3D"color: #660;" class=3D"s=
tyled-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> =C2=A0</span><span style=3D"color: #800;" class=3D"styled-by-pre=
ttify">// the output of the statement expression</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #660=
;" class=3D"styled-by-prettify">});</span></div></code></div></pre></div><d=
iv><br></div><div>A statement expression is executed directly inside its ca=
lling function. It does NOT create a new stack frame, so this works:</div><=
div><br></div><div class=3D"prettyprint" style=3D"background-color: rgb(250=
, 250, 250); border-color: rgb(187, 187, 187); border-style: solid; border-=
width: 1px; word-wrap: break-word;"><code class=3D"prettyprint"><div class=
=3D"subprettyprint"><span style=3D"color: #008;" class=3D"styled-by-prettif=
y">int</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> foo=
</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 s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"=
color: #008;" class=3D"styled-by-prettify">return</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;"=
 class=3D"styled-by-prettify">1</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">+</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">({</sp=
an><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">int</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> a </span><sp=
an style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> boo</span><span style=3D"c=
olor: #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">if</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">(!</span><span style=3D"color: #000;" cl=
ass=3D"styled-by-prettify">a</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 =C2=A0 </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">return</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">-</span><span style=3D"color: #066;" class=3D"styled-by-prettify=
">1</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> =C2=A0</span><s=
pan style=3D"color: #800;" class=3D"styled-by-prettify">// returns from foo=
()</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=
=A0 =C2=A0 a</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 </span><span style=3D"color: #660;" class=3D"styled-by-prettify">});</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">}</span></div></cod=
e></div><div><br></div><div><br></div><div>So what I have in mind is even w=
orse than this. I&#39;m thinking of proposing extending lambdas with some a=
ppalling new semantics:</div><div><br></div><div class=3D"prettyprint" styl=
e=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187)=
; border-style: solid; border-width: 1px; word-wrap: break-word;"><code cla=
ss=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008=
;" class=3D"styled-by-prettify">int</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> foo</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 </span><span style=3D"color: #008;" class=3D"styled-by-prettify">ret=
urn</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span=
><span style=3D"color: #066;" class=3D"styled-by-prettify">1</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">+</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">[!]{</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br>=C2=A0 =C2=A0 </span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> a </span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"> boo</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"=
>if</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(!</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify">a</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 =C2=A0 </span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">return</span><span=
 style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">-</span><span style=3D"color: #=
066;" class=3D"styled-by-prettify">1</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> =C2=A0</span><span style=3D"color: #800;" class=3D"styled=
-by-prettify">// returns from foo()</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br>=C2=A0 =C2=A0 a</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"><br>=C2=A0 </span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">}();</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">}</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br></span></div></code></div><div><br></div><div>The new &#39;!&#39; =
capturing flag means &quot;execute this in the stack frame of my caller&quo=
t;. Or rather, it means &quot;execute this in <b>one</b>=C2=A0stack frame a=
bove this lambda function&#39;s stack frame&quot; because yes, you can do m=
ultiple &#39;!&#39;:</div><div><br></div><div class=3D"prettyprint" style=
=3D"background-color: rgb(250, 250, 250); border-color: rgb(187, 187, 187);=
 border-style: solid; border-width: 1px; word-wrap: break-word;"><code clas=
s=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"color: #008;=
" class=3D"styled-by-prettify">void</span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> evil</span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">()</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
>=C2=A0 </span><span style=3D"color: #800;" class=3D"styled-by-prettify">//=
 Inject &quot;return 5;&quot; into whomever calls evil()</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br>=C2=A0 </span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">[!!]</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #66=
0;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">return</span><span style=3D"color: #000;" class=3D"styled-by=
-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify=
">5</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span st=
yle=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"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"> foo</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">()</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">{</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>=
=C2=A0 evil</span><span style=3D"color: #660;" class=3D"styled-by-prettify"=
>();</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =C2=
=A0</span><span style=3D"color: #800;" class=3D"styled-by-prettify">// as i=
f &quot;return 5;&quot;</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify"><br></span><span style=3D"color: #660;" class=3D"styled-by-pre=
ttify">}</span></div></code></div><div><br></div><div>And you can also do &=
#39;!!!&#39; or &#39;!!!!&#39; and so on up to the current inlineability li=
mit of the code currently being compiled.</div><div><br></div><div>I am ver=
y sure most reading will hate this proposal, and I am making it semi-seriou=
sly to see just how much people hate it before I describe it in P0779R0. Bu=
t what I would say in its favour is that it would solve the last remaining =
major use case for C macros in C++: injecting boilerplate into a caller&#39=
;s stack frame. And furthermore, I am unaware of <i>any other proposed alte=
rnative</i>=C2=A0for injecting boilerplate into a caller&#39;s stack frame =
<i>other</i>=C2=A0than C macros. Even Herb&#39;s metaclasses don&#39;t cove=
r this use case as far as I read them, which means we still will be using C=
 macros to achieve boilerplate injection in 2025.</div><div><br></div><div>=
And I don&#39;t know about you, but I&#39;d like to see the back of C macro=
s.</div><div><br></div><div>These &quot;evil lambdas&quot; would solve the =
problem. You basically get to alias a function call to expand into some boi=
lerplate, much tidier than C macro expansion because it follows normal C++ =
rules, not the preprocessor&#39;s weird rules. The availability of this fac=
ility would let one turn the Coroutines TS into an almost entirely library =
based implementation for example. My operator try idea is just injection of=
 boilerplate as well, it becomes much tidier with this facility in place. R=
anged for loops again can be implemented using these. Anywhere where we inj=
ect boilerplate, we can inject these instead and make them library implemen=
ted, not hard coded into the compiler.</div><div><br></div><div>But there a=
re also lots, and lots of other awful unforeseen consequences. Like you&#39=
;d surely have to allow evil lambdas which inject programmatically determin=
ed evil lambdas right? What kind of rabbit holes does that open up? Evil la=
mbdas can inject arbitrary new variables, modify existing ones, change cont=
rol flow, inject try and catch, basically do anything which C macros can do=
, but without the problems associated with C macros. What about ordering? S=
hould injection of evil lambda contents occur in the order of compilation? =
What if an evil lambda injects code three stack frames up which transforms =
the evil lambda doing the injecting? It would be easiest to just bail out, =
but it would be more <i>fun</i>=C2=A0if evil lambdas could recursively rewr=
ite themselves.</div><div><br></div><div>What do people think?</div><div><b=
r></div><div>Niall</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&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/3beae118-eaad-485e-835c-ecb19d145098%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/3beae118-eaad-485e-835c-ecb19d145098=
%40isocpp.org</a>.<br />

------=_Part_8525_619870399.1507676568869--

------=_Part_8524_716728600.1507676568868--

.