-
Notifications
You must be signed in to change notification settings - Fork 259
[SUGGESTION] Implement the pipeline operator from P2011 & P2672 #741
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
As soon as I see this, I think "hmm, like UFCS does?", and then I saw the example which looks suspiciously like UFCS for most of the cases. Clarifying questions, just so I understand the question (I haven't had time to watch the talk). Is the
would be the same as this using UFCS, which I think would work in Cpp2 now:
or something like that, modulo any late-night typos I wrote? |
That's right. Including
Can you remind me where |
|
Wow, that was fast. I was just trying to write the code for What about expressing this
as this
? Then it's all (I haven't tried to compile the code though.) |
There's some overlap between UFCS and this proposed pipeline operator. Conor's presentation shows off various range pipeline examples, but the P2011 and P2672 papers discuss the motivation and problem space. P2011 also discusses how it's different to UFCS. I think the key difference for Cpp2 is allowing the placeholder to appear in different argument positions in order to compose the range algorithms and views. |
Do you have a test? I had to add |
By the way, I just took the parameter of
(
|
I added one. |
That's not valid grammar (https://cpp2.godbolt.org/z/9avjYh6sb):
|
Yes -- in a racing update I was updating the comment to say the following, but I'll make it a separate reply instead: Right, that code is currently rejected because
modulo typos and bugs? Or maybe name it |
You're right that UFCS is very close already, and arguably the dot syntax is just as nice as the new operator, but with UFCS I'd still prefer a token to make the syntax simpler. (Perhaps
|
Excellent. auto filter_out_html_tags(std::string_view sv) {
return sv
|> transform($, [](auto e) { return e == '<' or e == '>'; })
|> zip_transform(std::logical_or{}, $, scan_left($, true, std::not_equal_to{}))
|> zip($, sv)
|> filter($, [](auto t) { return not std::get<0>(t); })
|> values($)
|> ranges::to<std::string>($);
} Text
|
IIRC, that proposal has seen push back |
Since there's talk about P2672, is there any interest for placeholder lambdas to replace the recently added |
Standalone So when you write We still have the problem of having to specify the behavior when Anyways, I think a simple |
Looks like it works on characters, indeed. |
@codereport FYI. |
The code in this comment should now parse correctly: #741 (comment)
Thanks! It's rare these days that I find a bug in the very first "load" step that tags which code is Cpp1 vs Cpp2, but this was one. I think it's fixed in this commit: 789cd38
Do you mean like Boost.Lambda's My concern with that is, would it be:
I could be persuaded to like
Does that make sense? |
I don't seem to have a C++ compiler installed on this machine that supports all of the new range/view things used in this example, because I'm mainly testing with a-few-years-old compilers to ensure compatibility. But if I understand correctly, the original example of this:
which could be written more simply using the proposed
works in Cpp2/cppfront today using just UFCS like this (with a helper
... Is that correct? |
That's right.
Yes, this works now.
|
[Edited to add that this also helps reduce need for library techniques like overloading Groovy, thanks. I've learned two major things from this thread:
|
Opened #746 for this. |
Well, my thinking was that the current new syntax was already kind of divergent. Yes, it is obtained by omitting parts but that ommitance is conflicting (omitting |
That's because when you're using the terse syntax,
|
After reading the paper above, I once again thought of this:
We have UFCS with semantics |
I find it very interesting that it takes only a single sentence in standardese to enable UFCS for
|
Right, I like the
Once you have both things specified, it's actually fairly easy in the first thing's specification to turn "else it's ill-formed" into "else try [second existing thing]"... great example of reuse. Same thing in cppfront, when all I have to do for a new feature is enable also looking at another existing thing (e.g., grammar production) it tends to be a few-line tactical change rather than a big surgery. That said, note that is only my own draft standardese wording, I still need a card-carrying Core language working group expert to check it 😏 . That said, it is based on language that ware Core-reviewed when a variation of this proposal last made it to plenary in 2016, just it was going the other (IMO wrong) way, having |
With regards to https://www.reddit.com/r/cpp/comments/17h7trm/p3027r0_ufcs_is_a_breaking_change_of_the/, I think the ADL woes, regardless of UFCS, are an orthogonal issue, best solved separately. |
All code written in cpp2 is new code, so ufcs can't be a breaking change for cpp2 code?
On 11 November 2023 15:31:38 Johel Ernesto Guerrero Peña ***@***.***> wrote:
With regards to https://www.reddit.com/r/cpp/comments/17h7trm/p3027r0_ufcs_is_a_breaking_change_of_the/,
how about changing the UFCS syntax to from using . to using .:?
E.g., obj.:func(args).
The : in .: comes from the ::s in the (implicit) name of a chosen non-member func
(e.g., could be ::func, ns::func when within ns, or the one in obj.:base::func(args)<#746 (comment)>).
I think the ADL woes, regardless of UFCS, are an orthogonal issue, best solved separately.
—
Reply to this email directly, view it on GitHub<#741 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AALUZQNGNI3EII2QTDSK2BDYD6K5PAVCNFSM6AAAAAA5ZQQZ32VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMBWHA2DKMRUHE>.
You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
|
Yeah, and the counter paper recognizes this. Moving code from Cpp1 to Cpp2 can introduce a breaking change. |
You could say it's needed for #748, |
In my opinion, having a different symbol for UFCS would reduce surprises and would make it an opt-in. So I strongly support this notion. |
I think a |> function($, b, c) // Proposal
a . function( b, c) // UFCS Cpp2 can have the good part of the proposal: The placeholder The placeholder Optional PlaceholderLet's consider the placeholder is optional. If we don't pass Also var1: = (x + y) * (x + y);
// It's the same as above. `it` is `(x + y)`.
var2: = (x + y) * it;
// The first `it` is `(x + y)`.
// The second `it` is `(x + y) * it`.
var3: = (x + y) * it * it;
var4: = ab.fnc1(it, it).fnc2(it, it);
var5: = ab.fnc1(ab).fnc2(ab.fnc1(ab)); And we can change the position of // : = fnc1(arg, obj);
var1: = obj.fnc1(arg, it); This feature improves chained UFCS without requiring to use additional helper function filter_out_html_tags_cpp2: (sv: std::string_view)
sv.transform(: (e) e == '<' || e == '>')
// .call(:(x) zip_transform(std::logical_or(), x, scan_left(x, true, std::not_equal_to()));)
.zip_transform(std::logical_or(), it, scan_left(it, true, std::not_equal_to()))
.zip(sv)
.filter(: (t) ! t.get<0>())
.values()
.to<std::string>(); If it's hard to find The point of the placeholder is that:
So I'm in favor of @bluetarpmedia's comment (but in a way that placeholder is optional):
|
In another words, the placeholder is optional. If var1: = ab.fnc1(mn, it);
// : = fnc1(mn, ab); Otherwise var1: = ab.fnc1(mn);
// : = fnc1(ab, mn); So we can have chained function calls regardless of whether |
Optional Placeholder SyntaxIf you find optional placeholders not to be readable, its readability may be increased by adding extra // : = obj.fnc1(this: = x, it);
// : = obj.fnc1(this? x, it);
var1: = obj.fnc1(this x, it); Briefly Without var1: = obj.fnc1(x, it); // ERROR! `it` keyword requires explicit `this` argument. And without var1: = obj.fnc1(x); // OK. It falls back to `fnc1(obj, x)`. The example from the proposal will be like this (with new syntax): filter_out_html_tags_cpp2: (sv: std::string_view)
sv.transform(: (e) e == '<' || e == '>')
// .call(:(x) zip_transform(std::logical_or(), x, scan_left(x, true, std::not_equal_to()));)
.zip_transform(this? std::logical_or(), it, scan_left(it, true, std::not_equal_to()))
.zip(sv)
.filter(: (t) ! t.get<0>())
.values()
.to<std::string>(); So optional placeholder doesn't conflict with the way UFCS works today, it complements it. Thanks. |
Suggestion to use 'lhs' instead of 'it' as keyword for this proposal. It is clearer as to the meaning of the value, and I found myself substituting 'it' for 'left hand side' in my head whenever I read it
On 15 November 2023 10:36:41 Sadeq ***@***.***> wrote:
Optional Placeholder Syntax
If you find optional placeholders not to be readable, it may increase readability by adding extra this like if it was a keyword argument (it depends on what will be the syntax of keyword arguments or designated constructors):
// : = obj.fnc1(this: = x, it);
// : = obj.fnc1(this? x, it);
var1: = obj.fnc1(this x, it);
Briefly A.F(this B, it) is equal to B.F(A) which it falls back to F(B, A). That's it. Thanks.
Without this, we cannot write it keyword in argument list:
var1: = obj.fnc1(x, it); // ERROR! `it` keyword requires explicit `this` argument.
And without it, UFCS will work as how we currently use it:
var1: = obj.fnc1(x); // OK. It falls back to `fnc1(obj, x)`.
So the placeholder doesn't conflict with the way UFCS works today, it complements it.
—
Reply to this email directly, view it on GitHub<#741 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AALUZQMNOYQDBIQY5TWNEDTYESLLLAVCNFSM6AAAAAA5ZQQZ32VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMJSGIYTGNRQGI>.
You are receiving this because you commented.Message ID: ***@***.***>
|
There is another use case.
|
From #748 (comment):
From #748 (comment):
|
The code in this comment should now parse correctly: hsutter#741 (comment)
The unary pipeline operator can be used for terse lambda syntax, i.e. |
* Add `..` syntax to select a member function only With this commit, `x.f()` is still UFCS, but `x..f()` will now find only a member function. For now I like that the default is UFCS, but as we get more experience I'm open to changing the default so that `.` is member selection and `..` is UFCS (which would be a breaking change, but a mechanical one). Also: Remove the old version of `get_declaration_of` now that the new lookup seems stable. * Remove some debug code * Finish removing old g_d_o paths
Suggestion
Cpp2 could support the pipeline operator
|>
as proposed in P2011 and further explored in P2672.Specifically, the pipeline operator with the "placeholder model" with mandatory placeholder (e.g.
$
), as described in P2672 section6 Disposition
. Both papers explain the problem and motivation for the new operator, as well as discussing options for the placeholder token.Circle uses
$
as its token.The proposed operator enables a simpler left-to-right style as opposed to an inside-out style.
Conor Hoekstra (code_report) has various talks about ranges and pipelines and explains how the pipeline operator can make the code simpler and more readable. The following is one of his examples:
Without the operator:
With the operator:
Will your feature suggestion eliminate X% of security vulnerabilities of a given kind in current C++ code?
No
Will your feature suggestion automate or eliminate X% of current C++ guidance literature?
No
Describe alternatives you've considered.
Alternatives are discussed at length in the two papers referenced above.
The text was updated successfully, but these errors were encountered: