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