• Why doesn't __VA_LIST__ just eat the prior comma?

    From Kaz Kylheku@21:1/5 to All on Thu Apr 14 00:01:37 2022
    There is a well-known problem that a macro like

    #define foo(x, ...) something(whatever, __VA_ARGS__)

    cannot work when the trailing argument list is empty because
    you get the expansion something(whatever, )

    GNU C provides ##__VA_ARGS__ which behaves like __VA_ARGS__ in
    the nonempty case, and eats the prior comma in the empty case.

    C++20 provides __VA_OPT__ which is used like __VA_OPT__(,) to
    conditionally eat the comma. (GNU C has this also).

    The question is: why wouldn't you just fix the semantics of __VA_ARG__
    so that this is not necessary?

    When would you ever want to interpolate __VA_ARGS__ into a replacement
    sequence such that if it is empty, and placed after a comma, that
    comma does not disappear?

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ben@21:1/5 to Kaz Kylheku on Thu Apr 14 14:17:22 2022
    Kaz Kylheku <480-992-1380@kylheku.com> writes:

    There is a well-known problem that a macro like

    #define foo(x, ...) something(whatever, __VA_ARGS__)

    cannot work when the trailing argument list is empty because
    you get the expansion something(whatever, )

    GNU C provides ##__VA_ARGS__ which behaves like __VA_ARGS__ in
    the nonempty case, and eats the prior comma in the empty case.

    C++20 provides __VA_OPT__ which is used like __VA_OPT__(,) to
    conditionally eat the comma. (GNU C has this also).

    The question is: why wouldn't you just fix the semantics of __VA_ARG__
    so that this is not necessary?

    When would you ever want to interpolate __VA_ARGS__ into a replacement sequence such that if it is empty, and placed after a comma, that
    comma does not disappear?

    You might not want it (as a design feature), but there is probably code
    out there that now depends on it. The C committee is very reluctant to
    break existing code, especially where the fix is more complex than
    "search for 'restrict' to check it's not used".

    --
    Ben.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Ben on Mon Apr 18 16:59:20 2022
    On 2022-04-14, Ben <ben.usenet@bsb.me.uk> wrote:
    Kaz Kylheku <480-992-1380@kylheku.com> writes:

    There is a well-known problem that a macro like

    #define foo(x, ...) something(whatever, __VA_ARGS__)

    cannot work when the trailing argument list is empty because
    you get the expansion something(whatever, )

    GNU C provides ##__VA_ARGS__ which behaves like __VA_ARGS__ in
    the nonempty case, and eats the prior comma in the empty case.

    C++20 provides __VA_OPT__ which is used like __VA_OPT__(,) to
    conditionally eat the comma. (GNU C has this also).

    The question is: why wouldn't you just fix the semantics of __VA_ARG__
    so that this is not necessary?

    When would you ever want to interpolate __VA_ARGS__ into a replacement
    sequence such that if it is empty, and placed after a comma, that
    comma does not disappear?

    You might not want it (as a design feature), but there is probably code
    out there that now depends on it.

    That's my question: what is the form of this dependency? What is an
    example of something that breaks if __VA_ARGS__ eats the prior comma
    when it has an empty expansion?

    Of course, we can write regression test cases which verify that
    the comma is not eaten, and I can think of ways of doing that:

    #define mac(...) foo(, __VA_ARGS__)
    #define xstr(x) str(x)
    #define str(x) #x

    assert (strcmp(xstr(mac()), "foo(, )") == 0);

    printf("%s\n", xstr(mac()));

    I mean, some way of relying on the comma that is actually useful.

    If I wanted to stringify mac() for some useful purpose in some real
    program, I would actually prefer the result "foo( )" or "foo()".
    I'd likely need a post-processing run-time pass to convert "(, )"
    occurrences to "()". I'd probably have some conditionals to do it
    in the preprocessor, so that the post-processing code can be
    compiled out.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Ben@21:1/5 to Kaz Kylheku on Mon Apr 18 20:43:09 2022
    Kaz Kylheku <480-992-1380@kylheku.com> writes:

    On 2022-04-14, Ben <ben.usenet@bsb.me.uk> wrote:
    Kaz Kylheku <480-992-1380@kylheku.com> writes:

    There is a well-known problem that a macro like

    #define foo(x, ...) something(whatever, __VA_ARGS__)

    cannot work when the trailing argument list is empty because
    you get the expansion something(whatever, )

    GNU C provides ##__VA_ARGS__ which behaves like __VA_ARGS__ in
    the nonempty case, and eats the prior comma in the empty case.

    C++20 provides __VA_OPT__ which is used like __VA_OPT__(,) to
    conditionally eat the comma. (GNU C has this also).

    The question is: why wouldn't you just fix the semantics of __VA_ARG__
    so that this is not necessary?

    When would you ever want to interpolate __VA_ARGS__ into a replacement
    sequence such that if it is empty, and placed after a comma, that
    comma does not disappear?

    You might not want it (as a design feature), but there is probably code
    out there that now depends on it.

    That's my question: what is the form of this dependency? What is an
    example of something that breaks if __VA_ARGS__ eats the prior comma
    when it has an empty expansion?

    I don't know of an example.

    Of course, we can write regression test cases which verify that
    the comma is not eaten, and I can think of ways of doing that:

    #define mac(...) foo(, __VA_ARGS__)
    #define xstr(x) str(x)
    #define str(x) #x

    assert (strcmp(xstr(mac()), "foo(, )") == 0);

    printf("%s\n", xstr(mac()));

    I mean, some way of relying on the comma that is actually useful.

    The code does not have to find it actually useful for it to break on a
    change. If someone, somewhere, ended up having to work around this
    issue, that code will break even if the programmer might now be glad of
    the opportunity to simplify it.

    --
    Ben.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Kaz Kylheku on Tue Apr 19 02:04:36 2022
    Kaz Kylheku <480-992-1380@kylheku.com> writes:

    There is a well-known problem that a macro like

    #define foo(x, ...) something(whatever, __VA_ARGS__)

    cannot work when the trailing argument list is empty because
    you get the expansion something(whatever, )

    GNU C provides ##__VA_ARGS__ which behaves like __VA_ARGS__ in
    the nonempty case, and eats the prior comma in the empty case.

    C++20 provides __VA_OPT__ which is used like __VA_OPT__(,) to
    conditionally eat the comma. (GNU C has this also).

    The question is: why wouldn't you just fix the semantics of
    __VA_ARG__ so that this is not necessary?

    This idea is considered in section "Alternative Designs" of

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2160.htm

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Tim Rentsch on Wed Apr 20 02:02:53 2022
    On 2022-04-19, Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:
    Kaz Kylheku <480-992-1380@kylheku.com> writes:

    There is a well-known problem that a macro like

    #define foo(x, ...) something(whatever, __VA_ARGS__)

    cannot work when the trailing argument list is empty because
    you get the expansion something(whatever, )

    GNU C provides ##__VA_ARGS__ which behaves like __VA_ARGS__ in
    the nonempty case, and eats the prior comma in the empty case.

    C++20 provides __VA_OPT__ which is used like __VA_OPT__(,) to
    conditionally eat the comma. (GNU C has this also).

    The question is: why wouldn't you just fix the semantics of
    __VA_ARG__ so that this is not necessary?

    This idea is considered in section "Alternative Designs" of

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2160.htm

    Fantastic; thanks for that link!

    The crux is that, for whatever reason, a macro like:

    #define ADD_COMMA(...) , __VA_ARGS__

    is tabled as an important requirement, and for that reason, F()
    expanding to f(10), though identified as desirable, is not considered;
    the automatic comma eating would break ADD_COMMA.

    But! I think that could be acceptably handled like this:

    #define FENCE
    #define ADD_COMMA(...) , FENCE __VA_ARGS__

    The rule that __VA_ARGS__ consumes the comma would be carried out
    prior to the macro replacement of the token replacement sequence,
    during which time FENCE is still there. Since FENCE doesn't look like
    a comma, all is cool.

    (This seems natural because the substitution of __VA_ARGS__ should in fact
    be taking place during argument replacement, and not during the
    rescanning of the argument-substituted replacement sequence for more
    macros.)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Tim Rentsch@21:1/5 to Kaz Kylheku on Sat May 14 10:35:12 2022
    Kaz Kylheku <480-992-1380@kylheku.com> writes:

    On 2022-04-19, Tim Rentsch <tr.17687@z991.linuxsc.com> wrote:

    Kaz Kylheku <480-992-1380@kylheku.com> writes:

    There is a well-known problem that a macro like

    #define foo(x, ...) something(whatever, __VA_ARGS__)

    cannot work when the trailing argument list is empty because
    you get the expansion something(whatever, )

    GNU C provides ##__VA_ARGS__ which behaves like __VA_ARGS__ in
    the nonempty case, and eats the prior comma in the empty case.

    C++20 provides __VA_OPT__ which is used like __VA_OPT__(,) to
    conditionally eat the comma. (GNU C has this also).

    The question is: why wouldn't you just fix the semantics of
    __VA_ARG__ so that this is not necessary?

    This idea is considered in section "Alternative Designs" of

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2160.htm

    Fantastic; thanks for that link!

    The crux is that, for whatever reason, a macro like:

    #define ADD_COMMA(...) , __VA_ARGS__

    is tabled as an important requirement, and for that reason, F()
    expanding to f(10), though identified as desirable, is not
    considered; the automatic comma eating would break ADD_COMMA.

    But! I think that could be acceptably handled like this:

    #define FENCE
    #define ADD_COMMA(...) , FENCE __VA_ARGS__

    The rule that __VA_ARGS__ consumes the comma would be carried out
    prior to the macro replacement of the token replacement sequence,
    during which time FENCE is still there. Since FENCE doesn't look
    like a comma, all is cool.

    If you feel strongly about it, write up a proposal and submit it
    to the two committees. Given that __VA_OPT__ has already been
    adopted in C++20, any alternate scheme faces an uphill climb, and
    so if no one feels strongly enough to try to get some other
    scheme through the standardization process then it seems rather
    pointless to discuss it.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)