You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[BUG] No way to declare std::function that use references in cpp2 #343
bug_std_function.cpp2(1,17): error: '*'/'const' type qualifiers must be followed by a type name or '_' wildcard (at '(')
bug_std_function.cpp2(1,19): error: missing function return after -> (at 'int')
I would like to be able use cpp2 function types as templates arguments, or function argument and return types.
From what I understand from the wiki my code should be written in the following way:
While I generally agree with the elimination of references in favor of in/out/inout arguments there should still be a way to spell them because they remain a part of the underlying object model - just doesn’t have to be particularly short.
min: (forward l: int, forward r: int) -> forward int = {
if l < r {
return l;
} else {
return r;
}
}
main: () = {
x := 0;
y := 1;
[[assert: min(x, y)& == x& ]]
y++; // this is needed to supress move from last use
}
@filipsajdak True, but I'm still looking for a way to correctly implement std::min in pure Cpp2.
I think this comment by @AbhinavK00 is the correct analysis.
Why in parameters? The above examples make perfect sense if we function takes something with size more than 2 pointers (I think it is any UDT now).
I think the right diagnosis isn't to ban forward return of in arguments but to pass the argument by reference everytime the function forward returns it. How would we write functions such as std::min etc. with this?
When we're forward returning an in parameter, it should be passed as const T& not cpp2::in<T>.
So Cpp2's implementation of std::min could look like
min: <T> (a: T, b: T) -> forward _ = {
if a < b {
return a;
}
else {
return b;
}
}
which will be compiled to
template <typename T>
automin(const T& a, const T& b) -> auto&& {
if (a < b) {
return a;
}
else {
return b;
}
}
This is pretty much what I already wrote in #248 (comment). What do you think?
Remember that the min of #343 (comment) is not a template. Although this may be similar to #193 (comment). How often do you write a non-templated function whose result is a read-only argument (so identity matters), that in parameter passing would optimize to pass by value (so it may not be future-proof or portable)?
How often do you write a non-templated function whose result is a read-only argument
The current design doesn't even allow us to write function templates that return an in argument.
Edit: Issue #317 which restores old behaviour of cpp2::in can also proceed with a check of whether the argument is being forward returned and then just pass it by const&.
I changed -> forward _ to -> forward T, honest to the signature of std::min.
Then I tried adding parentheses around the returned parameters. cppfront then accepts: https://godbolt.org/z/1M9asnh1c.
The generated code returns T&.
Changing back to -> forward _ makes the declared return type be auto&&, which results in working code: https://godbolt.org/z/rra8EW8z1.
Knowing that a declared return type of auto&& or decltype(auto), and redundant parentheses, can change meaning from "type and value category of the expression" to "declared type of the data member in the data member access expression" (see this "1)" and this "2)"), I next tried with a type: https://godbolt.org/z/Kszo8EPfc.
Looks like not using T directly as the parameter's type results in cppfront wrapping the declared parameter type in cpp2::in, which results in a parameter type that can't be deduced from its argument. That's #367.
I think the min example is a bit more involving than "just" a "reference". Some callers only care about the return value. Others, also about the identity of the returned reference. And being a reference to const, means being initializable from prvalues, which has its own set of implications.
Sometimes, the "what" is a reference. How do we spell that in Cpp2?
Do we really NEED to? I think the conventions in the paper do encompass all the use cases. A lanaguage like rust has 3 conventions and we can express everything (not really conventions but close), Val has a better model with 4 conventions and cppfront has 6. It's not like we were losing expressivity in any case until the decision was made to make in not forward returnable which I'd say was not well-thought.
Reacted by Junyoung Lee, Nick Treleaven and Jorge Canizales
Thanks! Catching up, the original example f2 now works with #1183, except you have to write the parameter name (i.e., it's a full function signature just as if you were writing a function, same syntax)... this now works:
Activity
JohelEGP commentedon Apr 9, 2023
Seems like there are no unnamed parameters: https://godbolt.org/z/zG7xGh3Kz.
Some test cases: https://godbolt.org/z/oxrhsecdq.
orent commentedon Apr 11, 2023
While I generally agree with the elimination of references in favor of in/out/inout arguments there should still be a way to spell them because they remain a part of the underlying object model - just doesn’t have to be particularly short.
How about std::reference or something similar?
JohelEGP commentedon Apr 11, 2023
I agree. I don't think you can rewrite this in pure Cpp2: https://godbolt.org/z/csKcPTrzx.
filipsajdak commentedon Apr 11, 2023
@JohelEGP not the same but works: https://godbolt.org/z/zKnn7re3d
leejy12 commentedon Apr 13, 2023
@filipsajdak But that
minimplementation won't work when passing rvalues.filipsajdak commentedon Apr 13, 2023
@leejy12 in that specific use case, it is a feature. You don't want to check an address to a temporary variable.
leejy12 commentedon Apr 13, 2023
@filipsajdak True, but I'm still looking for a way to correctly implement
std::minin pure Cpp2.I think this comment by @AbhinavK00 is the correct analysis.
When we're
forwardreturning aninparameter, it should be passed asconst T¬cpp2::in<T>.So Cpp2's implementation of
std::mincould look likewhich will be compiled to
This is pretty much what I already wrote in #248 (comment). What do you think?
JohelEGP commentedon Apr 13, 2023
Remember that the
minof #343 (comment) is not a template. Although this may be similar to #193 (comment). How often do you write a non-templated function whose result is a read-only argument (so identity matters), thatinparameter passing would optimize to pass by value (so it may not be future-proof or portable)?AbhinavK00 commentedon Apr 13, 2023
The current design doesn't even allow us to write function templates that return an
inargument.Edit: Issue #317 which restores old behaviour of
cpp2::incan also proceed with a check of whether the argument is being forward returned and then just pass it byconst&.JohelEGP commentedon Apr 13, 2023
I don't understand. Can you give an example?
AbhinavK00 commentedon Apr 13, 2023
From a comment in this issue only, the following isn't allowed in cpp2
min: <T> (a: T, b: T) -> forward _ = { if a < b { return a; } else { return b; } }AbhinavK00 commentedon Apr 13, 2023
From a comment in this issue only, the following isn't allowed in cpp2
min: <T> (a: T, b: T) -> forward _ = { if a < b { return a; } else { return b; } }JohelEGP commentedon Apr 13, 2023
You're right: https://godbolt.org/z/MaWdqG1dM.
I changed
-> forward _to-> forward T, honest to the signature ofstd::min.Then I tried adding parentheses around the returned parameters.
cppfrontthen accepts: https://godbolt.org/z/1M9asnh1c.The generated code returns
T&.Changing back to
-> forward _makes the declared return type beauto&&, which results in working code: https://godbolt.org/z/rra8EW8z1.Knowing that a declared return type of
auto&&ordecltype(auto), and redundant parentheses, can change meaning from "type and value category of the expression" to "declared type of the data member in the data member access expression" (see this "1)" and this "2)"), I next tried with a type: https://godbolt.org/z/Kszo8EPfc.Looks like not using
Tdirectly as the parameter's type results incppfrontwrapping the declared parameter type incpp2::in, which results in a parameter type that can't be deduced from its argument. That's #367.AbhinavK00 commentedon Apr 13, 2023
But aren't those just work-arounds? You're clearly violating a cpp2's rule, can also be thought of as a bug in transpiler, no?
JohelEGP commentedon Apr 13, 2023
Sometimes, the "what" is a reference. How do we spell that in Cpp2?
JohelEGP commentedon Apr 13, 2023
I think the
minexample is a bit more involving than "just" a "reference". Some callers only care about the return value. Others, also about the identity of the returned reference. And being a reference to const, means being initializable from prvalues, which has its own set of implications.AbhinavK00 commentedon Apr 13, 2023
Do we really NEED to? I think the conventions in the paper do encompass all the use cases. A lanaguage like rust has 3 conventions and we can express everything (not really conventions but close), Val has a better model with 4 conventions and cppfront has 6. It's not like we were losing expressivity in any case until the decision was made to make
innot forward returnable which I'd say was not well-thought.JohelEGP commentedon Apr 13, 2023
I do wonder. Maybe this calls for waiting for real world use-cases. Similar to how
copyis necessary.The OP's use case is just a bug/lack of feature, because there's no way to describe a function's type, like
(: std::string) -> std::string.JohelEGP commentedon Apr 24, 2023
See #387 (comment) for how the grammar may be change for this.
JohelEGP commentedon Jun 22, 2023
I was going to suggest this as a workaround while we wait for actual function type support: https://cpp2.godbolt.org/z/arEsxc3Gf.
But:
feat: accept function-type after type-id
feat: support function types
feat: support function types
feat: support function types
feat: support function types
hsutter commentedon Jul 27, 2024
Thanks! Catching up, the original example
f2now works with #1183, except you have to write the parameter name (i.e., it's a full function signature just as if you were writing a function, same syntax)... this now works:f2: () -> std::function<(x: std::string) -> std::string> = { // ok with #1183 return :(s : std::string) -> std::string = { return s + " World!"; }; } main: () = { std::cout << f2()("Hello"); // prints: Hello World! }