Skip to content

events: Add support for infering event type from Callback objects #3782

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

Merged
merged 2 commits into from
Feb 21, 2017

Conversation

geky
Copy link
Contributor

@geky geky commented Feb 15, 2017

While limitations in type inference prevent the event helper from infering the type of generic function objects, there is nothing technical preventing inference from the Callback class, where the function type is encoded in the template parameters.

With adoption of the Callback class as the standard function representation, it makes sense to support events created from callback objects.

This use case came up in client code that used a separate type for function pointers.
cc @pan- (I'm ccing you on anything with this much template stuff)

While limitations in type inference prevent the event helper from
infering the type of generic function objects, there is nothing
technical preventing inference from the Callback class, where the
function type is encoded in the template parameters.

With adoption of the Callback class as the standard function
representation, it makes sense to support events created from
callback objects.
@pan-
Copy link
Member

pan- commented Feb 16, 2017

@geky I'm not sure to understand bits like this one:

 template <typename R, typename B0, typename B1, typename B2, typename B3, typename C0, typename C1, typename C2, typename C3, typename A0, typename A1, typename A2, typename A3, typename A4>
    Event<void(A0, A1, A2, A3, A4)> event(mbed::Callback<R(B0, B1, B2, B3, A0, A1, A2, A3, A4)> cb, C0 c0, C1 c1, C2 c2, C3 c3);

What is expected for C types ? Should they be compatible ?

Also I'm not sure to understand why this change is needed because functions like:

    template <typename F, typename C0, typename C1, typename C2, typename C3>
    Event(EventQueue *q, F f, C0 c0, C1 c1, C2 c2, C3 c3) 

Should already swallow callbacks.

@geky
Copy link
Contributor Author

geky commented Feb 16, 2017

The extra C typenames are a workaround for some limitations of implicit casts/templates in C++. Basically, implicit casts don't occur when the variable is a templated type. Storing the bound arguments as separate types moves the implicit cast to the call site and avoids some weird types issues that are surprising:

void doit(unsigned value);
queue.event(doit, 1); // Error - 1 is signed without implicit casts-

This is the same design pattern used here: #3244


This patch is to allow callbacks in the EventQueue::event convenience functions. Before this patch, expressions like the following would not compile:

void (*doit)();
EventQueue queue;
Callback<void()> wrappeddoit = queue.event(doit); // This is fine

Callback<void()> doit;
EventQueue queue;
Callback<void()> wrappeddoit = queue.event(doit); // No overload of 'EventQueue::event' matches 'Callback<void()>'

The reason for this is that I haven't figured out how to infer the argument types for a generic F in c++03. In c++11 decltype makes this trivial, but my attempts in c++03 have mostly ended up with the compiler bailing (ARMmbed/mbed-events#24). If you have an idea to workaround this I'd be quite interested.

Without a mechanism to generically infer the argument types, the convenience functions (callback and EventQueue::event) have been limited to types where the arguments are encoded directly. Until now, this has just been the R (*f)(A...), R (*f)(T*, A...), and R (T::*f)(A...) style types, along with their cv-qualifiers. This patch adds support for Callback<R(A...)> as well, since it's the standard function type in mbed. (note the callback function already supports Callback<R(A...)> in the form of copy-construction).

@pan-
Copy link
Member

pan- commented Feb 17, 2017

The extra C typenames are a workaround for some limitations of implicit casts/templates in C++. Basically, implicit casts don't occur when the variable is a templated type. Storing the bound arguments as separate types moves the implicit cast to the call site and avoids some weird types issues that are surprising:

So C types should be convertible into B types, it would be nice to have it well documented. Also, to store references in the evenr it would be interesting to have equivalent to ref and cref (see here).

The reason for this is that I haven't figured out how to infer the argument types for a generic F in c++03. In c++11 decltype makes this trivial, but my attempts in c++03 have mostly ended up with the compiler bailing (ARMmbed/mbed-events#24). If you have an idea to workaround this I'd be quite interested.

Now I remember. This issue was more about the error experience rather than behavior.
It is possible to test if the F in input is a function pointer or a function like object (testing the call operator ) and get its arity but it is not trivial code by any mean.

@geky
Copy link
Contributor Author

geky commented Feb 17, 2017

C types should be convertible into B types, it would be nice to have it well documented. Also, to store references in the evenr it would be interesting to have equivalent to ref and cref (see here).

I tried to add better documentation for the binding types. I do want to avoid having too much information that may confuse users.

As for ref/cref, I gave up pretty early on trying to minimize copy operations. If the user passes anything not trivially-copyable (as would be expected by a function), they'll probably be in for a bad time.

I'm all for proper reference handling where possible, I just don't think I'm too interested in adding it until we can just adopt C++11.

@bridadan
Copy link
Contributor

@geky I'm removing the needs: CI label until you and @pan- are happy with this change. Please relabel this and start the morph bot when you're ready.

@pan-
Copy link
Member

pan- commented Feb 20, 2017

I tried to add better documentation for the binding types. I do want to avoid having too much information that may confuse users.

Thanks for the bit of documentation added.

As for ref/cref, I gave up pretty early on trying to minimize copy operations. If the user passes anything not trivially-copyable (as would be expected by a function), they'll probably be in for a bad time.

I'm all for proper reference handling where possible, I just don't think I'm too interested in adding it until we can just adopt C++11.

Even in C++11 keeping references as references is an operation that has to be explicitly done by the programmer. I'll make a PR for it; it is trivial.

@bridadan I've approve this PR, the factorization of Callables can come at a latter point.

@0xc0170
Copy link
Contributor

0xc0170 commented Feb 21, 2017

/morph test

@mbed-bot
Copy link

Result: SUCCESS

Your command has finished executing! Here's what you wrote!

/morph test

Output

mbed Build Number: 1666

All builds and test passed!

@sg- sg- merged commit 4103842 into ARMmbed:master Feb 21, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants