C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Alternative Free Function Calling Syntax.

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Mon, 29 Sep 2025 11:13:02 -0400
On Sun, Sep 28, 2025 at 11:13 AM Bad At The Game via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> Hi, I tried to take another approach at UFCS, Here
>
> https://github.com/ZXShady/proposals/blob/main/alternative_free_function_call_syntax.md
> It isn't professionally written I tried my best.
>

FYI, if you were to elevate this into an actual WG21 proposal, it would
need to have a real person's name on it, not "Shady".

FYI, your Clang patch
<https://github.com/llvm/llvm-project/compare/main...ZXShady:llvm-project:alternative_free_function_calling_syntax>
seems to have a lot of extraneous diffs. I bet you ran `clang-format` on
the entire codebase, or on the files you touched. Don't do that. Instead,
run `git-clang-format --diff --extensions ',h,cpp' HEAD~4 --` to format
only the exact diffs that you made, leaving the rest of the file's
formatting intact.

Consider hyperlinking to CWG 1089
<https://cplusplus.github.io/CWG/issues/1089.html> instead of the more
cumbersome CWG 1089
<https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1089>.

The idea seems identical to the pre-existing (and apparently
stalled/abandoned) P2011
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2011r1.html>
proposal of a "pipeline operator" — with two differences:
(1) You use the existing token `.` instead of P2011's new "pizza operator"
`|>` (which required lexers to change to accept `|>` as a single token).
(2) You limit the right-hand-side "operand" to begin lexically with `
*identifier* ::` in addition to whatever P2011 says.

Your discussion of CWG 1089 focuses on `p->T::f()`, not `p.T::f()`. Are you
trying to propose that `p -> T::f()` should act the same as your new `(*p)
. T::f()`, or differently from it? Either way seems bad. IMHO the original
sin here was trying to reuse `.` as the pipeline operator, instead of
picking a completely new operator like P2011's `|>`.

It's unclear to me (since you didn't provide wording) whether you intend to
support both
    int x1 = 1;
    int y1 = x . std::max(2);
(where lookup finds an overload set of function templates) and also
    int x2 = 1;
    int y2 = x . std::ranges::max(2);
(where lookup finds a single global variable, which happens to be a
niebloid). Ctrl+F for "ranges::", "nieb", "cpo" didn't find any discussion
of what you mean by "only finds free functions."

Come to think of it, it's also unclear what you would do with:
    struct S { int f(int); static float f(S&, int); };
    S s;
    int y3 = s . S::f(2);
Is this now going to be rewritten into `S::f(s, 2)`, or will you keep the
old behavior and make it call `s.f(2)`? Does anything change if the name
`S` in this context refers to a namespace? Godbolt:
<https://godbolt.org/z/1boz51v59>
    namespace N {
      struct S {
        int f(int) { return 1; }
        static int f(S&, int) { return 2; }
      };
    }
    namespace S {
      int f(N::S&, int) { return 3; }
    }
    int main() {
      N::S s;
      return s.S::f(2); // today this returns 1
    }
With P2011's pizza operator, the semantics are obvious (at least in this
case):
      return s |> S::f(2); // today this is illegal; tomorrow it rewrites
into S::f(s, 2) and therefore returns 3, no ambiguity at all

Basically, you have some minor procedural problems with the proposal, and
then you have a major fatal flaw due to your trying to reuse `.` (and maybe
`->`?) as your pipeline operator instead of inventing a new one.

–Arthur

Received on 2025-09-29 15:13:20