Closed geky closed 7 years ago
Maybe I misunderstand something here but I see two different concepts in the same class:
EventBuilder
: Construct an event in several steps, the post member function commit it to its event queue. It act like a builder and can be reused to post different events. Event
class.. callback_func(event)
and other variants might be enough (I know a workaround for the return type has to be found....).Otherwise it is an interesting enhancement.
Yep, I was hoping to kill two birds with one stone.
The goal is to encourage users to move as much code out of interrupt context as possible. Unfortunately, default behaviour is interrupt context, which makes it easy to suddenly find yourself in an interrupt. But we can encourage better behaviour through syntactic sugar.
Currently (with this patch), this is the easiest method to move events out of interrupt context:
Event<> event(queue, func);
ticker.attach(&event, &Event<>::call, 10);
However, this forces the use of method pointers, which can be intimidating to new users. With the operator()
overloaded, I would hope to see some syntactic sugar similar to the following emerge in the mbed codebase, allowing deferring from interrupts in a generic manner:
Event<> event(queue, func);
ticker.attach(event, 10);
If we want to avoid this syntax for now, I can split the function-like operations out into a different pr, which can stagnate until such overloads are added to mbed-os.
If we go this route, it would be beneficial to add a post_void
sort of member function that works around the return type as you mention. Allowing this as a temporary pattern:
Event<> event(queue, func);
ticker.attach(&event, &Event<>::post_void, 10);
What about:
operator Callback<void(A0,...)>() {
return Callback<void(A0,...)>(this, &Event<A0,...>::post_void);
}
It would still be possible to write:
Event<> event(queue, func);
ticker.attach(event, 10);
but not:
Event<> event(queue, func);
event();
What do you think ?
Hmm, that is a good idea.
My only concern is a running concern I've had with the clarity of ownership. It would be very easy for even an experienced user to take your example and expect the following to work:
EventQueue queue;
void setup() {
Event<> event(&queue, func);
ticker.attach(event, 10);
}
int main() {
setup();
queue.dispatch();
}
Looking into related concepts, it looks like the operator&
is actually overloadable.
As an alternative, what are you thoughts on instead adding a private EventPtr
sort of proxy object that is returned from operator&
and supports implicit casts to Callback
and Event*
? The above could be rewritten as follows, making the memory ownership a bit more clear:
EventQueue queue;
void setup() {
Event<> event(&queue, func);
ticker.attach(&event, 10);
}
int main() {
setup();
queue.dispatch();
}
My only concern is a running concern I've had with the clarity of ownership. It would be very easy for even an experienced user to take your example and expect the following to work.
100% agreed overloading operator&
is much better in that case.
@pan-, I've removed the operator()
and related functions, with the intention of considering compatibility with the Callback class in a different pr.
Any concerns with the updated pr?
For a more fine-grain control of event dispatch, the Event class can be manually instantiated and configured. An
Event
represents an event as a C++ style function object and can be directly passed to other APIs that expect a callback.From the updated readme:
cc @pan- thoughts?