Skip to content
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

p1214 - cAll the Things! - motivation, numbers, examples for C++29 #3

Open
Morwenn opened this issue Jan 17, 2019 · 12 comments
Open

p1214 - cAll the Things! - motivation, numbers, examples for C++29 #3

Morwenn opened this issue Jan 17, 2019 · 12 comments
Assignees
Labels
good first issue Good for newcomers help wanted Extra attention is needed orcs [design.ewg] To be mulled over by the rowdy, unpredictable, rambunctious featureists in Evolution. research Digging into the problem at hand
Milestone

Comments

@Morwenn
Copy link
Collaborator

Morwenn commented Jan 17, 2019

So, since P1214 isn't likely to move before we can present actual numbers from an actual implementation in a compiler, I'm opening this issue to gather all the feedback & numbers I can provide. That way when it may have chances to pass EWGI and not to die another sad death before EWG.

No need for the bloated <functional>

(this section is probably less impactful now that we have modules)

One thing that the paper does not mention is that <functional> is often included for std::invoke only [citation needed] and that <functional> is known for being one of the slowest headers to parse:

Modules might change this, but the world probably won't fully move to modules until build systems and IDEs are ready to handle them.

std::invoke is comparatively slow to compile

According to the benchmarks of Eggs.Invoke, std::invoke is 1.5 to 18 times slower to compile than an equivalent plain function call, and the compilation process uses up to 12 times as much memory. It is quite underwhelming for such a small fundamental function.

Better error messages

The feature isn't implemented yet in compilers, but using normal functions as examples should give an example of how error messages can be improved (is there a simple way to make Tony Tables GitHub issues?):

#include <functional>

void func(int) {}

int main()
{
    struct foo_t {} foo;
    std::invoke(func, foo);
}

This snippet gives the following output on the Compiler Explorer with GCC 8.2 :

<source>: In function 'int main()':
<source>:8:26: error: no matching function for call to 'invoke(void (&)(int), main()::foo_t&)'
     std::invoke(func, foo);
                          ^
In file included from <source>:1:
/opt/compiler-explorer/gcc-8.2.0/include/c++/8.2.0/functional:78:5: note: candidate: 'template<class _Callable, class ... _Args> std::invoke_result_t<_Callable, _Args ...> std::invoke(_Callable&&, _Args&& ...)'
     invoke(_Callable&& __fn, _Args&&... __args)
     ^~~~~~
/opt/compiler-explorer/gcc-8.2.0/include/c++/8.2.0/functional:78:5: note:   template argument deduction/substitution failed:

With Clang 7:

<source>:8:5: error: no matching function for call to 'invoke'
    std::invoke(func, foo);
    ^~~~~~~~~~~
/opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/functional:78:5: note: candidate template ignored: substitution failure [with _Callable = void (&)(int), _Args = <foo_t &>]: no type named 'type' in 'std::invoke_result<void (&)(int), foo_t &>'
    invoke(_Callable&& __fn, _Args&&... __args)
    ^
1 error generated.

And with MSVC 19.16:

<source>(8): error C2672: 'std::invoke': no matching overloaded function found
<source>(8): error C2893: Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...) noexcept(<expr>)'
<source>(8): note: With the following template arguments:
<source>(8): note: '_Callable=void (__cdecl &)(int)'
<source>(8): note: '_Types={main::foo_t &}'

Now take the same snippet but without std::invoke:

void func(int) {}

int main()
{
    struct foo_t {} foo;
    func(foo);
}

Here is the error message with GCC 8.2:

<source>: In function 'int main()':
<source>:6:10: error: cannot convert 'main()::foo_t' to 'int'
     func(foo);
          ^~~
<source>:1:11: note:   initializing argument 1 of 'void func(int)'
 void func(int) {}
           ^~~

With Clang 7:

<source>:6:5: error: no matching function for call to 'func'
    func(foo);
    ^~~~
<source>:1:6: note: candidate function not viable: no known conversion from 'struct foo_t' to 'int' for 1st argument
void func(int) {}
     ^

And with MSVC 19.16:

<source>(6): error C2664: 'void func(int)': cannot convert argument 1 from 'main::foo_t' to 'int'
<source>(6): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

It should give a good idea of how the proposal should be able to improve error messages. It is worth noting that no compiler actually points to the definition of func on failure when std::invoke is used.

A better debugging experience

Some areas such as the video game industry have a need for interactive debugging and fast debug builds. Release builds tend to collapse calls to std::invoke into the appropriate underlying function call, but debug builds need to retain information about std::invoke and its helper functions.

Having language support for callables removes the aforementioned unneeded extra debug information - and hence can help reducing the size of the debug binary -, but also allows for a smoother navigation through function calls when debugging. In the current state of things, debugger implementers can "ignore" std::invoke as some already ignore std::move and std::forward and jump into std::function::operator() for the sake of a smoother debug navigation, but having language support would give the same experience without requiring implementers to tweak their debuggers.

Once generic libraries start moving away from std::invoke to generic language callables, it might drive their adoption in the areas that require a smoother debugging experience.

Links about issues with the debugging experience:

There might be more special cases in the future

In P0847R2, it is mentioned that the new kinds of member functions proposed don't follow the usual rules of member function pointers and give the following example:

struct Y {
    int f(int, int) const&;
    int g(this Y const&, int, int);
};

Y y;
y.f(1, 2); // ok as usual
y.g(3, 4); // ok, this paper

auto pf = &Y::f;
pf(y, 1, 2);              // error: pointers to member functions are not callable
(y.*pf)(1, 2);            // okay, same as above
std::invoke(pf, y, 1, 2); // ok

auto pg = &Y::g;
pg(y, 3, 4);              // okay, same as above
(y.*pg)(3, 4);            // error: pg is not a pointer to member function
std::invoke(pg, y, 3, 4); // ok

This means that depending on how you declare your member function, you might get different results on how it is possible to invoke a pointer to it. I think that it's yet another case where P1214 makes things better overall. It might be something worth mentioning in P0847 if the authors are fine with it.

Related proposals

P2826 mentions that this proposal could be useful to pointer-to-member-functions directly for their proposed replacement function feature.

It makes library implementers life easier

Once library implementers (including standard library ones) start relying on this feature, it will free there time to implement you favourite features faster! :D

(don't include this one in the paper)

@ThePhD ThePhD self-assigned this Jan 17, 2019
@ThePhD ThePhD added this to the C++23 milestone Jan 18, 2019
@ThePhD ThePhD added help wanted Extra attention is needed research Digging into the problem at hand labels Jan 18, 2019
@ThePhD ThePhD changed the title P1214: motivation, numbers, examples... p1214: motivation, numbers, examples... Jan 18, 2019
@ThePhD ThePhD added the good first issue Good for newcomers label Jan 18, 2019
@ThePhD ThePhD changed the title p1214: motivation, numbers, examples... p1214 - cAll the Things! - motivation, numbers, examples Jan 18, 2019
@Morwenn
Copy link
Collaborator Author

Morwenn commented Jan 18, 2019

Got you some examples of error messages that show how things might be improved :)

@ThePhD
Copy link
Owner

ThePhD commented Jan 18, 2019

Thanks, I'll try to Tony Table them.

Note I don't think I will submit this paper for Pre-Kona? Since it doesn't seem like it's worth adding to the mailing list pile to churn. (Maybe by the time Cologne or Belfast roll around, or the meeting after that?) This will certainly help when I start working on Dang (Derpstorm Clang, haaaah).

@Morwenn
Copy link
Collaborator Author

Morwenn commented Jan 18, 2019

I don't think it's worth updating it before you intend to present bring it again before EWGI, unless you want to gather more feedback from other places before that :p

Also great pun, I love it ❤️

@ThePhD ThePhD changed the title p1214 - cAll the Things! - motivation, numbers, examples p1214 - cAll the Things! - motivation, numbers, examples for C++23 Jan 19, 2019
@Morwenn
Copy link
Collaborator Author

Morwenn commented Jan 26, 2019

Deducing this and its rules for member function pointer just gave us some more free motivation :)

@Morwenn
Copy link
Collaborator Author

Morwenn commented Feb 4, 2019

We probably need to check which debuggers ignore std::invoke and which ones make you step through each step (I know that the MSVC debugger at least ignores std::move, std::forward and std::function to make life easier, not sure about std::invoke). That could be additional motivation.

@ThePhD
Copy link
Owner

ThePhD commented Feb 4, 2019

I'll make sure to add that to the paper soon, thanks for pointing it out Morwenn!

@ThePhD
Copy link
Owner

ThePhD commented Feb 6, 2019

Alternative title: "Removing Barriers to Entry: std::invoke for the masses".

@ThePhD
Copy link
Owner

ThePhD commented Feb 6, 2019

Alternative title: "Projections for everybody: better call syntax for Callables".

@Morwenn
Copy link
Collaborator Author

Morwenn commented Feb 7, 2019

It's somehow the easiest and least important argument in the mix, but we could mention that it would also probably help greatly simplifying the standard wording itself in some places x)

Your wording only introduces the one required to get the feature into the standard, but imagine the heaps of INVOKE stuff that could be removed everywhere. Maybe that should come with another paper though.

@ThePhD ThePhD added orcs [design.ewg] To be mulled over by the rowdy, unpredictable, rambunctious featureists in Evolution. and removed orcs [design.ewg] To be mulled over by the rowdy, unpredictable, rambunctious featureists in Evolution. labels Jun 10, 2019
@Morwenn
Copy link
Collaborator Author

Morwenn commented Aug 27, 2019

I'm reading the proposal again and I think that there is an impact on the standard that you didn't mention: INVOKE - and therefore std::invoke - should mirror the proposed language change to make pmo(obj, new_value); assign new_value to obj when pmo is a pointer to a member object.

@Morwenn
Copy link
Collaborator Author

Morwenn commented Aug 24, 2020

I'm adding this link to the motivation under a new section about compile time: https://eggs-cpp.github.io/invoke/benchmark.html

@ThePhD
Copy link
Owner

ThePhD commented Sep 25, 2020

Numbers on a better invoke: https://github.com/eggs-cpp/invoke

Someone started working on a compiler version of this. I'll probably do my own in GCC and Clang too...

@ThePhD ThePhD changed the title p1214 - cAll the Things! - motivation, numbers, examples for C++23 p1214 - cAll the Things! - motivation, numbers, examples for C++29 Jun 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers help wanted Extra attention is needed orcs [design.ewg] To be mulled over by the rowdy, unpredictable, rambunctious featureists in Evolution. research Digging into the problem at hand
Projects
None yet
Development

No branches or pull requests

2 participants