• ({

    From Alan Mackenzie@acm@muc.de to comp.lang.c++ on Thu Mar 20 18:27:26 2025
    From Newsgroup: comp.lang.c++

    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).

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Fri Mar 21 09:58:53 2025
    From Newsgroup: comp.lang.c++

    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?


    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paavo Helde@eesnimi@osa.pri.ee to comp.lang.c++ on Fri Mar 21 12:54:31 2025
    From Newsgroup: comp.lang.c++

    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.



    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Keith Thompson@Keith.S.Thompson+u@gmail.com to comp.lang.c++ on Fri Mar 21 12:27:59 2025
    From Newsgroup: comp.lang.c++

    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 */
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Sat Mar 22 10:09:19 2025
    From Newsgroup: comp.lang.c++

    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.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Alan Mackenzie@acm@muc.de to comp.lang.c++ on Sat Mar 22 10:53:41 2025
    From Newsgroup: comp.lang.c++

    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).

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Alan Mackenzie@acm@muc.de to comp.lang.c++ on Sat Mar 22 11:00:34 2025
    From Newsgroup: comp.lang.c++

    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).

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Alan Mackenzie@acm@muc.de to comp.lang.c++ on Sat Mar 22 11:26:31 2025
    From Newsgroup: comp.lang.c++

    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).

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From scott@scott@slp53.sl.home (Scott Lurndal) to comp.lang.c++ on Sat Mar 22 14:09:21 2025
    From Newsgroup: comp.lang.c++

    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.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Bonita Montero@Bonita.Montero@gmail.com to comp.lang.c++ on Sat Mar 22 16:14:42 2025
    From Newsgroup: comp.lang.c++

    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.

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Paavo Helde@eesnimi@osa.pri.ee to comp.lang.c++ on Sat Mar 22 17:18:58 2025
    From Newsgroup: comp.lang.c++

    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());


    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Alan Mackenzie@acm@muc.de to comp.lang.c++ on Sat Mar 22 15:20:35 2025
    From Newsgroup: comp.lang.c++

    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).

    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From scott@scott@slp53.sl.home (Scott Lurndal) to comp.lang.c++ on Sat Mar 22 15:53:50 2025
    From Newsgroup: comp.lang.c++

    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.
    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From David Brown@david.brown@hesbynett.no to comp.lang.c++ on Sat Mar 22 17:45:49 2025
    From Newsgroup: comp.lang.c++

    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.



    --- Synchronet 3.20c-Linux NewsLink 1.2
  • From Jakob Bohm@egenagwemdimtapsar@jbohm.dk to comp.lang.c++ on Tue Apr 1 06:59:03 2025
    From Newsgroup: comp.lang.c++

    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.
    --- Synchronet 3.20c-Linux NewsLink 1.2