-
Notifications
You must be signed in to change notification settings - Fork 260
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
Add function call inout passing style - closes #231 #294
Add function call inout passing style - closes #231 #294
Conversation
@hsutter, one side note. You use Lines 3250 to 3252 in fbf55ad
It should adjust the position of the argument ( Lines 5609 to 5618 in fbf55ad
Unfortunately, in the case of function argument Line 3252 in fbf55ad
The issue is that the Line 589 in fbf55ad
adjust_remaining_token_columns_on_this_line_visitor::start method except first argument will be const , and adjust_remaining_token_columns_on_this_line_visitor expects token& .
Should I report it as a separate issue? |
Does it? It still doesn't match the set expectations:
To be able to do that, "move from last use" should inspect that the call would be well-formed with a |
I did a dirty hack and I used v.start(*const_cast<token*>(identifier), depth+1); The Something is not working. |
Its not like we don't need
Last use of our variable is not when we pass it onto the function but when we actually print the result. |
An |
Ah yes, sorry for the mistake so in this case we should probably get the suggestion to change the parameter passing convention to |
No, the problem still exists. It's just that the function's body is irrelevant, as the problem is on the call side.
You're right, but the linked issue hints at a more general problem. #198, which Herb refers to in his reply, suggests that more would be needed to support As it stands, the |
@AbhinavK00, you are correct about that it should be
This issue is about something else. The correct version of this code is following: f2: (inout x) -> _ = {
x *= 2;
return x;
}
main: () -> int = {
x := 21;
std::cout << f2(inout x) << std::endl;
} To suppress the move on the last use of I propose to use |
As @JohelEGP pointed out, this change does seem like a work-around and we probably need a more general solution for the more general problem. I would propose the the following change, what do you think about it
Yes, this would lose performance on some use cases but there are not really cases where you don't use the value after modifying it, I mean why modify it in first place if you won't use it again, that's just bad code. Should've been some form of |
After sleeping over this topic, I see some of the issues here. E.g., I would expect that call: fun(inout x); Will NOT match the following functions: fun_in: (in x) -> _ {/* ... */} // now matches
fun_copy: (copy x) -> _ {/* ... */} // now matches
fun_move: (move x) -> _ {/* ... */} // now does not match
fun_out: (out x) -> _ {/* ... */} // now does not match And SHOULD match the following: fun_inout: (inout x) -> _ {/* ... */} // now matches
fun_forward: (forward x) -> _ {/* ... */} // now matches I thought about it a little more and thought, what if we will require explicit argument passing on the call side (except for
fun_out(out x); // similar to above declaration
fun_copy(copy x); // symmetry
fun_in(x); // also symmetry as function can be declared as fun_in:(x) = ...
I draw a matrix on potential matches between explicit argument passing on the call site vs. match to function declaration:
What do you think? |
Edit: About |
@AbhinavK00 if you ask about function declaration and why it uses |
@filipsajdak , the paper only talks about 5 passing conventions mainly |
@AbhinavK00 Oh, sorry. I was sure that it was described in the paper as well... I quickly searched what was discussed with @hsutter in the issues/PRs. Please take a look here: #76 (comment) Sorry for misleading you. |
Ok, so Herb tried to keep The user can always pass in a copy if he wants to any kind of function, so he'll just do
when he wants to pass a copy. |
7861132
to
9f3c7db
Compare
Thanks for picking this up again. I'm going to reply on the original thread for #231... see you over there. |
With this feature being on verge on getting merged, I think I'll start the talk about syntax here. I know Herb says not to worry about syntax but I think once features make it into the language, its hard to bring changes in them. So here it is
func_call(arg1@, arg2@); We put a suffix symbol after the argument name to symbolise "modification". It could be any symbol, I just used
move_func_call(arg1!@);
move_func_call(arg1@@); You may notice that both of the above options have the user using two symbols, it's because moving should be more "visible" than modification as it is an operation to be careful about.
foward_func_call_out(arg@); //forwarding to an out function
forward_func_call_inout(arg@); //forwarding to an inout function
forward_func_call_move(arg!@); //forwarding to a move function
//no worries about implementation, we just express our intent
func(arg.copy()); We just copy our object and pass it along. Reason Symbols considered for using b := obj.addr(); //similar to ssize, huh
c := addr(obj); //less elegant While both ways would be legal, the first way (present thanks to UFCS) is more similar to how we write it today but with some more keystrokes. With that, the syntax would look like this: func_in(arg);
func_out(arg&);
func_inout(arg&);
func_move_1(arg!&); // or
func_move_2(arg&&);
func_copy(arg.copy());
//nothing special for forward
//BONUS
v := a!&; // similar to cpp's auto v = std::move(a);
//anymore you could think of With Also, this is NOT similar to @filipsajdak 's suggestion where marking and not marking arguments do different things. Here, we HAVE to mark arguments in all cases as specified above. Not marking the arguments (if it is not |
@AbhinavK00 Just to be sure, by "these two could be unified", are you referring just to the potential decoration syntax on the caller side, and not merging the two on the function declaration/definition? |
@gregmarr , yes just on the caller side. That comment proposes for no change on the callee side that we already have in cpp2. |
This discussion sounds vaguely familiar but I can't find it. Do you have a reference? |
Here, thanks to @filipsajdak |
In current implementation of cppfront the following code ```cpp f2: (inout x) -> _ = { return x * 2; } main: () -> int = { x := 21; std::cout << f2(x) << std::endl; } ``` Generates: ```cpp [[nodiscard]] auto f2(auto& x) -> auto{ return x * 2; } [[nodiscard]] auto main() -> int{ auto x {21}; std::cout << f2(std::move(x)) << std::endl; } ``` and fail to compile as move from last use make the call to `f2` incompatible with requirements of the `f2` function (function requires lvalue reference and receives rvalue reference). This change introduce possibility to add `inout` passing style to function call to emphasize that it has to be passed without the move. After this change the original code can be fixed to: ```cpp f2: (inout x) -> _ = { return x * 2; } main: () -> int = { x := 21; std::cout << f2(inout x) << std::endl; } ``` which will generate: ```cpp [[nodiscard]] auto f2(auto& x) -> auto{ return x * 2; } [[nodiscard]] auto main() -> int{ auto x {21}; std::cout << f2( x) << std::endl; } ```
9f3c7db
to
57f5453
Compare
I need to work more on that to include comments from the issue: #231 |
In the current implementation of cppfront, the following code
Generates:
and fail to compile as move from last use make the call to
f2
incompatible with requirements of thef2
function (function requires lvalue reference and receives rvalue reference).This change introduces the possibility of adding an
inout
passing style to function call to emphasize that it has to be passed without the move.After this change, the original code can be fixed to:
Which will generate:
Closes #231 - all regression tests pass.