3 ms·
The author has been trying to push for the inclusion of nested functions into the C standard, and a lot of the resistance comes from the existence of trampoline
by jcranmer 25d ago
The author has been trying to push for the inclusion of nested functions into the C standard, and a lot of the resistance comes from the existence of trampolines and all of the issues that causes. His response to those issues is... to basically go "nested functions, Objective-C blocks, and C++ lambdas are all the same thing if you squint at them hard enough" and ignore all of the very real semantic differences between all of them.
For my part, I'll point out that there is one rather important difference between nested functions and C++ lambdas that the author completely ignores, as exhibited by this godbolt example: https://godbolt.org/z/35beWrrTe https://godbolt.org/z/35beWrrTe (note the differences in the generated assembly, especially that which cannot be explained merely by -O0 code generation).
- aw1621107 25d ago> note the differences in the generated assembly, especially that which cannot be explained merely by -O0 code generation Do you mind elaborating for those of us who aren't familiar with what to expect from the compiler?
- jcranmer 25d agoIn the nested function, the variable x is passed in edi, and the pointer to the nested stack frame is passed in r10. In the lambda, the variable x is passed in esi, and the 'this' pointer for the lambda is passed in rdi. The function-level ABIs end up being quite different.
- uecker 25d agoThanks, but now you should explain why you think this slight (and well understood) difference in calling convention is a rather important difference.
- tptacek 25d agoDoesn't this imply that the two functions have different semantics for capturing the environment?
- uecker 25d agoNo, why? It simply means that the arguments are in different registers.
- jcranmer 25d agoI can write the signature of the generated function of a C++ lambda as a C function. I cannot write the signature of a generated GCC nested function as a C function. If your argument is that ABI doesn't matter, then by all means, propose a patch to GCC to change the ABI and see if it gets accepted.
- uecker 25d agoI can not write the signature of a function that requires a static chain (which exist in many languages) in C, because we have not added such a feature to the language. But we could. And we should, because we now need a (type-unsafe) extension (__builtin_call_with_static_chain) to invoke such functions. I do not want to change the ABI for nested functions as it is a useful ABI and a cross-language standard. ABI obviously matters, but it is not a fundamental difference in implementation that makes nested functions fundamentally different to C++ lambdas. If your point is merely that a compiler translating nested functions to lambdas would need to adapt the ABI in this case, I agree. This is not difficult though. And this question is relevant only if one allows taking the address of a nested function, because as long as it is called only locally, the compiler can use whatever ABI it wants.
- jcranmer 25d agoOkay, so you accept that nested functions have a different ABI than C++ lambdas. And it looks like you accept that neither ABI is going to change. So long as the two features have different ABIs, they cannot be compatible with one another. > And this question is relevant only if one allows taking the address of a nested function And that question is very relevant since taking the address of such functions (to pass to other functions, e.g., qsort) is one of the main use cases for their existence.
- uecker 25d agoThe ABI does not need to be compatible, because there is no way to call a C++ lambda directly from C. If you take the address of a lambda function you get a pointer to an object of anonymous type, so you can not pass it to qsort, and qsort would also not know how to call this. But if we added a feature similar to std::function_ref to C (i.e. a wide function pointer type), then such a type could be used to call both, nested functions and C++'s lambdas, and - in fact - many callable entities from other languages too. But for C++'s lambdas this would always involve a compiler generated thunk that adapts the ABI. This is also exactly what happens in C++ if you use std::function, because even in C++ you can not pass the address of lambda to a function without first erasing the type and creating the thunk. So there is no compatibility problem.
- uecker 25d agoI am not the only one who wants nested functions and function literals (lambdas) in C (as in basically any other modern language) and I explained every time that trampolines are not needed for this. It is frankly quite tiring that every time this topic comes up, still someone incorrectly claims that we can not have nested functions because of trampolines, or makes some other incorrect claim on how GCC implements nested functions. BTW: I also very carefully analyzed all the semantic differences, which led me to the conclusion that putting C++ lambda semantics into C would be a bad idea. one can read this here: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3654.pdf https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3654.pdf I also do not understand why you think the generated assembly needs to be identical, or why this is a "rather important difference".