Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c++ > #122015 > unrolled thread
| Started by | Alan Mackenzie <acm@muc.de> |
|---|---|
| First post | 2025-03-20 18:27 +0000 |
| Last post | 2025-04-01 06:59 +0200 |
| Articles | 15 — 7 participants |
Back to article view | Back to comp.lang.c++
({ Alan Mackenzie <acm@muc.de> - 2025-03-20 18:27 +0000
Re: ({ Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-21 09:58 +0100
Re: ({ Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-22 16:14 +0100
Re: ({ Paavo Helde <eesnimi@osa.pri.ee> - 2025-03-21 12:54 +0200
Re: ({ Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2025-03-21 12:27 -0700
Re: ({ Bonita Montero <Bonita.Montero@gmail.com> - 2025-03-22 10:09 +0100
Re: ({ Alan Mackenzie <acm@muc.de> - 2025-03-22 11:26 +0000
Re: ({ Alan Mackenzie <acm@muc.de> - 2025-03-22 11:00 +0000
Re: ({ Alan Mackenzie <acm@muc.de> - 2025-03-22 10:53 +0000
Re: ({ scott@slp53.sl.home (Scott Lurndal) - 2025-03-22 14:09 +0000
Re: ({ Alan Mackenzie <acm@muc.de> - 2025-03-22 15:20 +0000
Re: ({ scott@slp53.sl.home (Scott Lurndal) - 2025-03-22 15:53 +0000
Re: ({ Paavo Helde <eesnimi@osa.pri.ee> - 2025-03-22 17:18 +0200
Re: ({ David Brown <david.brown@hesbynett.no> - 2025-03-22 17:45 +0100
Re: ({ Jakob Bohm <egenagwemdimtapsar@jbohm.dk> - 2025-04-01 06:59 +0200
| From | Alan Mackenzie <acm@muc.de> |
|---|---|
| Date | 2025-03-20 18:27 +0000 |
| Subject | ({ |
| Message-ID | <vrhmme$8v0$1@news.muc.de> |
Hello, C++.
I'm having some difficulty (amending Emacs's C++ Mode) reconciling the
two conflicting uses in C++ of ({.
Firstly, it is used as a "statement expression", a GCC enhancement also
found in C, allowing a more relaxed and natural way to write an
expression as the end result of a sequence of statements:
({ int y = foo (); int z;
if (y > 0) z = y;
else z = - y;
z; })
. I think this usage is very old.
Secondly, there's initialisation expressions like:
void f4 (int a, int b, int c)
{
std::vector<ABC> abcList2(
{{a+6,
b+6,
c+6}
}
);
....
}
. Here the ( on the std::vector line, together with the next {, can be
confused as a statement expression, though it's clearly not meant that
way. I think this syntax is much newer than the other one, though I may
be wrong here.
In calculating the indentation for source lines in these constructs, the
ambiguity causes mis-indentation for one or the other of them.
Now to my question: how common is GCC's statement expression in the wide
world of C++ source code? How much would be lost if I simply removed the
statement expression from C++ Mode's parsing functions?
--
Alan Mackenzie (Nuremberg, Germany).
[toc] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2025-03-21 09:58 +0100 |
| Message-ID | <vrj9o2$176cr$1@raubtier-asyl.eternal-september.org> |
| In reply to | #122015 |
Am 20.03.2025 um 19:27 schrieb Alan Mackenzie:
> Hello, C++.
>
> I'm having some difficulty (amending Emacs's C++ Mode) reconciling the
> two conflicting uses in C++ of ({.
>
> Firstly, it is used as a "statement expression", a GCC enhancement also
> found in C, allowing a more relaxed and natural way to write an
> expression as the end result of a sequence of statements:
>
> ({ int y = foo (); int z;
> if (y > 0) z = y;
> else z = - y;
> z; })
If the sign of y is badly predictible you may chose:
z = (y >> sizeof(y) * CHAR_BIT - 1) * y;
> . I think this usage is very old.
>
> Secondly, there's initialisation expressions like:
>
> void f4 (int a, int b, int c)
> {
> std::vector<ABC> abcList2(
> {{a+6,
> b+6,
> c+6}
> }
> );
> ....
> }
>
> . Here the ( on the std::vector line, together with the next {, can be
> confused as a statement expression, though it's clearly not meant that
> way. I think this syntax is much newer than the other one, though I may
> be wrong here.
>
> In calculating the indentation for source lines in these constructs, the
> ambiguity causes mis-indentation for one or the other of them.
>
> Now to my question: how common is GCC's statement expression in the wide
> world of C++ source code? How much would be lost if I simply removed the
> statement expression from C++ Mode's parsing functions?
>
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2025-03-22 16:14 +0100 |
| Message-ID | <vrmk4n$7524$1@raubtier-asyl.eternal-september.org> |
| In reply to | #122016 |
Am 21.03.2025 um 09:58 schrieb Bonita Montero:
>> ({ int y = foo (); int z;
>> if (y > 0) z = y;
>> else z = - y;
>> z; })
> If the sign of y is badly predictible you may chose:
> z = (y >> sizeof(y) * CHAR_BIT - 1) * y;
Sorry, your code is more efficient since it can be substituted by
a negate i a second register and a conditional move. But some archi-
tectures like RISC-V don't have conditional moves and my code would
be the most efficient way to handle this.
[toc] | [prev] | [next] | [standalone]
| From | Paavo Helde <eesnimi@osa.pri.ee> |
|---|---|
| Date | 2025-03-21 12:54 +0200 |
| Message-ID | <vrjgh8$1bqpn$1@dont-email.me> |
| In reply to | #122015 |
On 20.03.2025 20:27, Alan Mackenzie wrote:
> Hello, C++.
>
> I'm having some difficulty (amending Emacs's C++ Mode) reconciling the
> two conflicting uses in C++ of ({.
>
> Firstly, it is used as a "statement expression", a GCC enhancement also
> found in C, allowing a more relaxed and natural way to write an
> expression as the end result of a sequence of statements:
>
> ({ int y = foo (); int z;
> if (y > 0) z = y;
> else z = - y;
> z; })
>
> . I think this usage is very old.
>
> Secondly, there's initialisation expressions like:
>
> void f4 (int a, int b, int c)
> {
> std::vector<ABC> abcList2(
> {{a+6,
> b+6,
> c+6}
> }
> );
> ....
> }
>
> . Here the ( on the std::vector line, together with the next {, can be
> confused as a statement expression, though it's clearly not meant that
> way. I think this syntax is much newer than the other one, though I may
> be wrong here.
This braced initialization (called "List-initialization") was introduced
in C++11, it is standardized and in wide and growing use.
>
> In calculating the indentation for source lines in these constructs, the
> ambiguity causes mis-indentation for one or the other of them.
>
> Now to my question: how common is GCC's statement expression in the wide
> world of C++ source code? How much would be lost if I simply removed the
> statement expression from C++ Mode's parsing functions?
It appears the statement expressions are a gcc extension which does not
even compile in standard C++, and is probably not needed for anything in
C++ as there are better options like templated and inlined functions.
In C there might be some usage case for it.
During the last 25 years I do not recall having encountered this feature
ever, and I do not even recall anyone bashing it. So I guess it could be
ditched pretty easily.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2025-03-21 12:27 -0700 |
| Message-ID | <87ldsyqj40.fsf@nosuchdomain.example.com> |
| In reply to | #122017 |
Paavo Helde <eesnimi@osa.pri.ee> writes:
[...]
> It appears the statement expressions are a gcc extension which does
> not even compile in standard C++, and is probably not needed for
> anything in C++ as there are better options like templated and inlined
> functions.
> In C there might be some usage case for it.
[...]
Statement expressions don't compile in *standard* C or C++.
gcc supports them as an extension for both C and C++ (and Objective-C).
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Bonita Montero <Bonita.Montero@gmail.com> |
|---|---|
| Date | 2025-03-22 10:09 +0100 |
| Message-ID | <vrlunj$3kg23$1@raubtier-asyl.eternal-september.org> |
| In reply to | #122018 |
Am 21.03.2025 um 20:27 schrieb Keith Thompson: > Statement expressions don't compile in *standard* C or C++. In C++ you could use lambdas for that.
[toc] | [prev] | [next] | [standalone]
| From | Alan Mackenzie <acm@muc.de> |
|---|---|
| Date | 2025-03-22 11:26 +0000 |
| Message-ID | <vrm6p7$2ue$3@news.muc.de> |
| In reply to | #122019 |
Bonita Montero <Bonita.Montero@gmail.com> wrote:
> Am 21.03.2025 um 20:27 schrieb Keith Thompson:
>> Statement expressions don't compile in *standard* C or C++.
> In C++ you could use lambdas for that.
The sort of thing statement expressions are good at are the likes of (C
example):
while ({
ch = getch ();
ch = toupper (ch);
ch != 'Q';
})
switch (ch) {
....
}
, the loop of a command processing function which takes single case
insensitive commands from the keyboard. While it is true that this
example could be rewritten using the comma operator in place of the
statement expression, it would only need to be slightly more complicated
to make this impractical.
Yes, in C++, a lambda could be used instead, but this is somewhat
artificial and would have more boilerplate cluttering up the actual code.
Anyhow, I haven't actually done any real C++ hacking for about 20 years,
I just try to keep Emacs's C++ Mode working.
--
Alan Mackenzie (Nuremberg, Germany).
[toc] | [prev] | [next] | [standalone]
| From | Alan Mackenzie <acm@muc.de> |
|---|---|
| Date | 2025-03-22 11:00 +0000 |
| Message-ID | <vrm58i$2ue$2@news.muc.de> |
| In reply to | #122018 |
Keith Thompson <Keith.S.Thompson+u@gmail.com> wrote:
> Paavo Helde <eesnimi@osa.pri.ee> writes:
> [...]
>> It appears the statement expressions are a gcc extension which does
>> not even compile in standard C++, and is probably not needed for
>> anything in C++ as there are better options like templated and inlined
>> functions.
>> In C there might be some usage case for it.
> [...]
> Statement expressions don't compile in *standard* C or C++.
More precisely, they're not standard C or C++. I think it is a shame
they never became part of the standard, as no doubt their developers
intended.
> gcc supports them as an extension for both C and C++ (and Objective-C).
There are instances of statement expressions in the Linux kernel,
developed under GCC, and clang was enhanced to support them too so as to
be able to compile Linux. Or so I've heard.
> --
> Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
> void Void(void) { Void(); } /* The recursive call of the void */
--
Alan Mackenzie (Nuremberg, Germany).
[toc] | [prev] | [next] | [standalone]
| From | Alan Mackenzie <acm@muc.de> |
|---|---|
| Date | 2025-03-22 10:53 +0000 |
| Message-ID | <vrm4rl$2ue$1@news.muc.de> |
| In reply to | #122017 |
Paavo Helde <eesnimi@osa.pri.ee> wrote:
> On 20.03.2025 20:27, Alan Mackenzie wrote:
>> Hello, C++.
>> I'm having some difficulty (amending Emacs's C++ Mode) reconciling the
>> two conflicting uses in C++ of ({.
>> Firstly, it is used as a "statement expression", a GCC enhancement also
>> found in C, allowing a more relaxed and natural way to write an
>> expression as the end result of a sequence of statements:
>> ({ int y = foo (); int z;
>> if (y > 0) z = y;
>> else z = - y;
>> z; })
>> . I think this usage is very old.
>> Secondly, there's initialisation expressions like:
>> void f4 (int a, int b, int c)
>> {
>> std::vector<ABC> abcList2(
>> {{a+6,
>> b+6,
>> c+6}
>> }
>> );
>> ....
>> }
>> . Here the ( on the std::vector line, together with the next {, can be
>> confused as a statement expression, though it's clearly not meant that
>> way. I think this syntax is much newer than the other one, though I may
>> be wrong here.
> This braced initialization (called "List-initialization") was introduced
> in C++11, it is standardized and in wide and growing use.
Yes, thanks.
>> In calculating the indentation for source lines in these constructs, the
>> ambiguity causes mis-indentation for one or the other of them.
>> Now to my question: how common is GCC's statement expression in the wide
>> world of C++ source code? How much would be lost if I simply removed the
>> statement expression from C++ Mode's parsing functions?
> It appears the statement expressions are a gcc extension which does not
> even compile in standard C++, and is probably not needed for anything in
> C++ as there are better options like templated and inlined functions.
> In C there might be some usage case for it.
I'm not sure what you meant by templated functions here, but an inline
function has the disadvantage of fragmenting the code. Rather than have
a few lines of code where they're used, you need to look somewhere else
to see what they do.
There are some uses of the statement expression in the (C) Linux kernel
sources.
> During the last 25 years I do not recall having encountered this feature
> ever, and I do not even recall anyone bashing it. So I guess it could be
> ditched pretty easily.
Thanks, that was what I thought. But in the last couple of days, I might
have come up with a way to parse both of the ({ constructs without (too
much) ambiguity.
--
Alan Mackenzie (Nuremberg, Germany).
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2025-03-22 14:09 +0000 |
| Message-ID | <lwzDP.1208305$_N6e.415187@fx17.iad> |
| In reply to | #122020 |
Alan Mackenzie <acm@muc.de> writes: >Paavo Helde <eesnimi@osa.pri.ee> wrote: >> On 20.03.2025 20:27, Alan Mackenzie wrote: >> It appears the statement expressions are a gcc extension which does not >> even compile in standard C++, and is probably not needed for anything in >> C++ as there are better options like templated and inlined functions. >> In C there might be some usage case for it. > >I'm not sure what you meant by templated functions here, but an inline >function has the disadvantage of fragmenting the code. Rather than have >a few lines of code where they're used, you need to look somewhere else >to see what they do. An inline function name should be chosen such that it is sufficient to define exactly what the effect of the function call will be, while still hiding the implementation and improving readability.
[toc] | [prev] | [next] | [standalone]
| From | Alan Mackenzie <acm@muc.de> |
|---|---|
| Date | 2025-03-22 15:20 +0000 |
| Message-ID | <vrmkg3$308h$2@news.muc.de> |
| In reply to | #122023 |
Scott Lurndal <scott@slp53.sl.home> wrote: > Alan Mackenzie <acm@muc.de> writes: >>Paavo Helde <eesnimi@osa.pri.ee> wrote: >>> On 20.03.2025 20:27, Alan Mackenzie wrote: >>> It appears the statement expressions are a gcc extension which does not >>> even compile in standard C++, and is probably not needed for anything in >>> C++ as there are better options like templated and inlined functions. >>> In C there might be some usage case for it. >>I'm not sure what you meant by templated functions here, but an inline >>function has the disadvantage of fragmenting the code. Rather than have >>a few lines of code where they're used, you need to look somewhere else >>to see what they do. > An inline function name should be chosen such that it is sufficient to > define exactly what the effect of the function call will be, while > still hiding the implementation and improving readability. Yes, that's fine in theory. In practice, meaning while debugging, a whole lot of midget functions, each called something like convert_next_char_to_upper_case_is_it_Q_p is a nightmare. That name is more difficult to understand than the three lines of code (see another of my posts in this thread) it replaces. While debugging, _nothing_ can be trusted to do what it says, and a hidden implementation makes things worse - rather than having to scroll a window to the inline function, it's probably in a different file. Even a single midget function which isn't a coherent thing makes debugging more irksome than simply having the three lines of code physically in the larger function where they are actually used. -- Alan Mackenzie (Nuremberg, Germany).
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2025-03-22 15:53 +0000 |
| Message-ID | <i2BDP.304568$SVG3.140032@fx42.iad> |
| In reply to | #122026 |
Alan Mackenzie <acm@muc.de> writes:
>Scott Lurndal <scott@slp53.sl.home> wrote:
>> Alan Mackenzie <acm@muc.de> writes:
>>>Paavo Helde <eesnimi@osa.pri.ee> wrote:
>>>> On 20.03.2025 20:27, Alan Mackenzie wrote:
>
>>>> It appears the statement expressions are a gcc extension which does not
>>>> even compile in standard C++, and is probably not needed for anything in
>>>> C++ as there are better options like templated and inlined functions.
>>>> In C there might be some usage case for it.
>
>>>I'm not sure what you meant by templated functions here, but an inline
>>>function has the disadvantage of fragmenting the code. Rather than have
>>>a few lines of code where they're used, you need to look somewhere else
>>>to see what they do.
>
>> An inline function name should be chosen such that it is sufficient to
>> define exactly what the effect of the function call will be, while
>> still hiding the implementation and improving readability.
>
>Yes, that's fine in theory. In practice, meaning while debugging, a
>whole lot of midget functions, each called something like
>convert_next_char_to_upper_case_is_it_Q_p is a nightmare.
Strawman. Nobody suggested that a meaningful name
requires forty characters.
inline bool is_ep(void) const { return flags & PCC_EP;}
is perfectly cromulent.
Gdb() has no problem stepping through that, and shows the
corresponding source.
[toc] | [prev] | [next] | [standalone]
| From | Paavo Helde <eesnimi@osa.pri.ee> |
|---|---|
| Date | 2025-03-22 17:18 +0200 |
| Message-ID | <vrmkd2$67va$1@dont-email.me> |
| In reply to | #122020 |
On 22.03.2025 12:53, Alan Mackenzie wrote:
> Paavo Helde <eesnimi@osa.pri.ee> wrote:
>> It appears the statement expressions are a gcc extension which does not
>> even compile in standard C++, and is probably not needed for anything in
>> C++ as there are better options like templated and inlined functions.
>> In C there might be some usage case for it.
>
> I'm not sure what you meant by templated functions here, but an inline
> function has the disadvantage of fragmenting the code. Rather than have
> a few lines of code where they're used, you need to look somewhere else
> to see what they do.
At the GCC page for statement expressions they say "This feature is
especially useful in making macro definitions “safe” (so that they
evaluate each operand exactly once)" and most of their examples are
about macros.
A macro is fragmenting the code exactly in the same way as an inline
function, except the macros are worse than functions in multiple ways.
In C one might argue macros are needed for supporting multiple types at
the same time, but in C++ this is solved much better by function templates.
Ergo, a C-style macro using statement expressions can easily replaced
with a more regular and better behaving function or function template in
C++, with no increase in code "fragmentation".
For "in-place" use Bonita is right a lambda can be used to the same
effect, but the readability probably does not go better. As per the
first example on the GCC page (poor man implementation of abs()):
int a = ({ int y = foo (); int z; if (y > 0) z = y; else z = - y; z; });
can be written with a lambda in C++:
int a = [](){int y = foo (); int z; if (y > 0) z = y; else z = - y;
return z; }();
I suspect Bonita might like this. I still prefer the more mundane
int a = std::abs(foo());
[toc] | [prev] | [next] | [standalone]
| From | David Brown <david.brown@hesbynett.no> |
|---|---|
| Date | 2025-03-22 17:45 +0100 |
| Message-ID | <vrmpft$a537$1@dont-email.me> |
| In reply to | #122025 |
On 22/03/2025 16:18, Paavo Helde wrote:
> On 22.03.2025 12:53, Alan Mackenzie wrote:
>> Paavo Helde <eesnimi@osa.pri.ee> wrote:
>>> It appears the statement expressions are a gcc extension which does not
>>> even compile in standard C++, and is probably not needed for anything in
>>> C++ as there are better options like templated and inlined functions.
>>> In C there might be some usage case for it.
>>
>> I'm not sure what you meant by templated functions here, but an inline
>> function has the disadvantage of fragmenting the code. Rather than have
>> a few lines of code where they're used, you need to look somewhere else
>> to see what they do.
>
> At the GCC page for statement expressions they say "This feature is
> especially useful in making macro definitions “safe” (so that they
> evaluate each operand exactly once)" and most of their examples are
> about macros.
>
> A macro is fragmenting the code exactly in the same way as an inline
> function, except the macros are worse than functions in multiple ways.
> In C one might argue macros are needed for supporting multiple types at
> the same time, but in C++ this is solved much better by function templates.
>
> Ergo, a C-style macro using statement expressions can easily replaced
> with a more regular and better behaving function or function template in
> C++, with no increase in code "fragmentation".
>
> For "in-place" use Bonita is right a lambda can be used to the same
> effect, but the readability probably does not go better. As per the
> first example on the GCC page (poor man implementation of abs()):
>
> int a = ({ int y = foo (); int z; if (y > 0) z = y; else z = - y; z; });
>
It can also combine well with type inference, such as the example from
GCC's reference:
#define max(a, b) \
({ __auto_type _a = (a); __auto_type _b = (b); \
_a > _b ? _a : _b; })
(In C23, "auto" is approximately equivalent to "auto" in C++, so you
don't need the gcc "__auto_type" extension any more.)
Of course such function-like macros are usually best replaced with
template functions in C++. I can't think off-hand of a situation where
statement expressions in C++ would be significantly better than either
an inline function / function template, or an immediately-invoked lambda.
[toc] | [prev] | [next] | [standalone]
| From | Jakob Bohm <egenagwemdimtapsar@jbohm.dk> |
|---|---|
| Date | 2025-04-01 06:59 +0200 |
| Message-ID | <vsfrqn$28p75$1@dont-email.me> |
| In reply to | #122017 |
On 2025-03-21 11:54, Paavo Helde wrote:
> On 20.03.2025 20:27, Alan Mackenzie wrote:
>> Hello, C++.
>>
>> I'm having some difficulty (amending Emacs's C++ Mode) reconciling the
>> two conflicting uses in C++ of ({.
>>
>> Firstly, it is used as a "statement expression", a GCC enhancement also
>> found in C, allowing a more relaxed and natural way to write an
>> expression as the end result of a sequence of statements:
>>
>> ({ int y = foo (); int z;
>> if (y > 0) z = y;
>> else z = - y;
>> z; })
>>
>> . I think this usage is very old.
>>
>> Secondly, there's initialisation expressions like:
>>
>> void f4 (int a, int b, int c)
>> {
>> std::vector<ABC> abcList2(
>> {{a+6,
>> b+6,
>> c+6}
>> }
>> );
>> ....
>> }
>>
>> . Here the ( on the std::vector line, together with the next {, can be
>> confused as a statement expression, though it's clearly not meant that
>> way. I think this syntax is much newer than the other one, though I may
>> be wrong here.
>
> This braced initialization (called "List-initialization") was introduced
> in C++11, it is standardized and in wide and growing use.
>
Actually, it is from K&R C, except (perhaps) the option to put the list
expression in a pair of regular parenthesis with the usual identical
meaning. The basic K&R form is:
int smallprimes[4] = { 2, 3, 5, 7 };
int identitymatrix[2][2] = { { 1, 0 }, { 0, 1 } };
In ANSI C, these can be declared const and placed in a read-only part of
the resulting program file. This was broken by the desire to allocate
all data on the heap via heap-centric classes like vector<int> .
Enjoy
Jakob
--
Jakob Bohm, MSc.Eng., I speak only for myself, not my company
This public discussion message is non-binding and may contain errors
All trademarks and other things belong to their owners, if any.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c++
csiph-web