-
Notifications
You must be signed in to change notification settings - Fork 249
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
[BUG] No way to declare std::function that use references in cpp2 #343
Comments
Seems like there are no unnamed parameters: https://godbolt.org/z/zG7xGh3Kz.
Some test cases: https://godbolt.org/z/oxrhsecdq.
|
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? |
I agree. I don't think you can rewrite this in pure Cpp2: https://godbolt.org/z/csKcPTrzx. using Int = const int&;
min: (l: Int, r: Int) -> Int = {
if l < r {
return l;
} else {
return r;
}
}
main: () = {
x := 0;
y := 1;
[[assert: min(x, y)& == x& ]]
} |
@JohelEGP not the same but works: https://godbolt.org/z/zKnn7re3d 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 But that |
@leejy12 in that specific use case, it is a feature. You don't want to check an address to a temporary variable. |
@filipsajdak True, but I'm still looking for a way to correctly implement
When we're So Cpp2's implementation of
which will be compiled to template <typename T>
auto min(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 |
The current design doesn't even allow us to write function templates that return an |
I don't understand. Can you give an example? |
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;
}
} |
1 similar comment
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;
}
} |
You're right: https://godbolt.org/z/MaWdqG1dM. I changed Changing back to Knowing that a declared return type of
|
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? |
Sometimes, the "what" is a reference. How do we spell that in Cpp2? |
I think the |
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 |
I do wonder. Maybe this calls for waiting for real world use-cases. Similar to how The OP's use case is just a bug/lack of feature, because there's no way to describe a function's type, like |
See #387 (comment) for how the grammar may be change for this. |
I was going to suggest this as a workaround while we wait for actual function type support: https://cpp2.godbolt.org/z/arEsxc3Gf.
But:
|
Uses the same grammar for functions, _function-type_. Parameter identifiers must be named `_` and can't be omitted. It's generally needed to specify the `throws` qualifier so that it doesn't lower to a `noexcept` function type. Some examples: ```Cpp2 main: () = { f0: * () throws = :() = {}; f6: * (move _: i32) throws = :(move x: i32) = {}; [[assert: inspect f0 -> bool { is () = (std::terminate(), false); is * () throws = true; is _ = false; }]] } // Test case from hsutter#343. f2: () -> std::function<(_: std::string) throws -> std::string> = { return :(s: std::string) -> std::string = { return s + " World!"; }; } // Adapted from <https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators>. f: (x: i32) -> * (_: i32) throws -> std::string = +:(x: i32) -> std::string = ""; postfix_operators: () = { [[assert: f is (_: i32) throws -> * (_: i32) throws -> std::string]] // / | | // / | | [[assert: f(42) is * (_: i32) throws -> std::string]] // ________________/ | // / | [[assert: f(42)* is (_: i32) throws -> std::string]] // _______________/ // / [[assert: (f(42)*)(1) is std::string]] } ```
Add _function-type_ as an alternative production of _type-id_. A parameter's identifier must be named `_`. `throws` needs to be specified for non Cpp1-`noexcept` function types. Some examples: ```Cpp2 main: () = { f0: * () throws = :() = {}; f7: * (move _: i32) throws = :(move x: i32) = {}; [[assert: inspect f0 -> bool { is () = (std::terminate(), false); is * () throws = true; is _ = false; }]] } // Test case from hsutter#343. f2: () -> std::function<(_: std::string) throws -> std::string> = { return :(s: std::string) -> std::string = { return s + " World!"; }; } // Adapted from <https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators>. f: (x: i32) -> * (_: i32) throws -> std::string = +:(x: i32) -> std::string = ""; postfix_operators: () = { [[assert: f is (_: i32) throws -> * (_: i32) throws -> std::string]] // / | | // / | | [[assert: f(42) is * (_: i32) throws -> std::string]] // ________________/ | // / | [[assert: f(42)* is (_: i32) throws -> std::string]] // _______________/ // / [[assert: (f(42)*)(1) is std::string]] } ```
Add _function-type_ as an alternative production of _type-id_. A parameter's identifier must be named `_`. `throws` needs to be specified for non Cpp1-`noexcept` function types. Some examples: ```Cpp2 main: () = { f0: * () throws = :() = {}; f7: * (move _: i32) throws = :(move x: i32) = {}; [[assert: inspect f0 -> bool { is () = (std::terminate(), false); is * () throws = true; is _ = false; }]] } // Test case from hsutter#343. f2: () -> std::function<(_: std::string) throws -> std::string> = { return :(s: std::string) -> std::string = { return s + " World!"; }; } // Adapted from <https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators>. f: (x: i32) -> * (_: i32) throws -> std::string = +:(x: i32) -> std::string = ""; postfix_operators: () = { [[assert: f is (_: i32) throws -> * (_: i32) throws -> std::string]] // / | | // / | | [[assert: f(42) is * (_: i32) throws -> std::string]] // ________________/ | // / | [[assert: f(42)* is (_: i32) throws -> std::string]] // _______________/ // / [[assert: (f(42)*)(1) is std::string]] } ```
Add _function-type_ as an alternative production of _type-id_. A parameter's identifier must be named `_`. `throws` needs to be specified for non Cpp1-`noexcept` function types. Some examples: ```Cpp2 main: () = { f0: * () throws = :() = {}; f7: * (move _: i32) throws = :(move x: i32) = {}; [[assert: inspect f0 -> bool { is () = (std::terminate(), false); is * () throws = true; is _ = false; }]] } // Test case from hsutter#343. f2: () -> std::function<(_: std::string) throws -> std::string> = { return :(s: std::string) -> std::string = { return s + " World!"; }; } // Adapted from <https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators>. f: (x: i32) -> * (_: i32) throws -> std::string = +:(x: i32) -> std::string = ""; postfix_operators: () = { [[assert: f is (_: i32) throws -> * (_: i32) throws -> std::string]] // / | | // / | | [[assert: f(42) is * (_: i32) throws -> std::string]] // ________________/ | // / | [[assert: f(42)* is (_: i32) throws -> std::string]] // _______________/ // / [[assert: (f(42)*)(1) is std::string]] } ```
Add _function-type_ as an alternative production of _type-id_. A parameter's identifier must be named `_`. `!throws` needs to be specified for Cpp1-`noexcept` function types. Some examples: ```Cpp2 main: () = { f0: * () = :() = {}; f7: * (move _: i32) = :(move x: i32) = {}; [[assert: inspect f0 -> bool { is () !throws = (std::terminate(), false); is * () = true; is _ = false; }]] } // Test case from hsutter#343. f2: () -> std::function<(_: std::string) -> std::string> = { return :(s: std::string) -> std::string = { return s + " World!"; }; } // Adapted from <https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators>. f: (x: i32) -> * (_: i32) -> std::string = :(x: i32) -> std::string = ""; postfix_operators: () = { [[assert: f is (_: i32) -> * (_: i32) -> std::string]] // / | | // / | | [[assert: f(42) is * (_: i32) -> std::string]] // _________/ | // / | [[assert: f(42)* is (_: i32) -> std::string]] // ________/ // / [[assert: (f(42)*)(1) is std::string]] }
Thanks! Catching up, the original example 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!
} |
In the current implementation of cppfront (5fa2707) in cpp2, there is no way to declare
std::function
that uses references.The following examples failed to work:
The last example passes cppfront, but generates different types of arguments:
I have also tried the code that was presented on the wiki (https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators#-and-)
but it also failed:
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:
The text was updated successfully, but these errors were encountered: