-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Remove problematic templated overloads on callback-based functions #2395
Conversation
Before this commit, the following pattern was suggested as a shortcut for writing callback-based functions overloaded based on arguments: template <typename T, typename M> void attach(T *obj, M method) { attach(Callback<void()>(obj, method); } Unfortunately, C++ did not fair well with this level of type-inference. The initial problems were with variable-arity function. The M type would happily consume arguments during overload-resolution, only to fail during template-expansion. Removed from problematic functions, this bug was unfortunately easy to reintroduce (for example in the RtosTimer) since it is undectable without forcing the template to expand. The latest problem is occuring during type-deduction of overloaded function pointers. The extra level of indirection with the templated- method parameter caused type-deduction to stop early, erroring with an ambiguity error. Even more unfortunate, this error is inconsistent, since some functions were unable to adopt the template-method pattern for the variable-arity issue mentioned earlier. For example: class Thing { void doit(int timeout); void doit(); }; Thing t; serial.attach(&t, &Thing::doit); // perfectly fine timer.attach(&t, &Thing::doit); // ambiguity compile error After running into these issues with this design pattern, the best path forward seems to be to simply remove the templated-method overloads. These have been replaced by the two explicit overloads for the existing callback arguments.
The EventLoop was an interesting concept: the combination of an EventQueue and a Thread. The idea was that the EventLoop would provide a convenient coupling of these two concepts for use in module boundaries, and the EventLoop could abstract out some of the complexities with running an event queue in a thread. However, with the addition of the chain function, event queues can be easily composed without threads or indirect references to event queues. Threads can still be spawned dynamically in default-constructors, although the overhead is much more explicit and tangible. Additionally, it turned out there weren't that many complexities with running an event queue in a thread. There were, surprisingly, several problems with just passing the EventQueue::dispatch function to mbed's Thread constructor. 1. Split EventQueue::dispatch into overloaded functions Apparently, default parameters don't create another target for infering member-function-pointers. 2. Remove problematic template overloads in Thread constructor Issue is actually here ARMmbed/mbed-os#2395. The indirection in the nested callback templates prevented correct overload resolution and let to template-expansion errors. 3. Exposed break_ Allows threaded event queues to shutdown cleanly. With these changes, this code: EventLoop loop; loop.start(); loop.call(F); loop.stop(); Becomes: EventQueue queue; Thread thread; thread.start(&queue, &EventQueue::dispatch); queue.call(F); queue.break_(); thread.join(); Except now with 182 less lines to maintain
The EventLoop was an interesting concept: the combination of an EventQueue and a Thread. The idea was that the EventLoop would provide a convenient coupling of these two concepts for use in module boundaries, and the EventLoop could abstract out some of the complexities with running an event queue in a thread. However, with the addition of the chain function, event queues can be easily composed without threads or indirect references to event queues. Threads can still be spawned dynamically in default-constructors, although the overhead is much more explicit and tangible. Additionally, it turned out there weren't that many complexities with running an event queue in a thread. There were, surprisingly, several problems with just passing the EventQueue::dispatch function to mbed's Thread constructor. 1. Split EventQueue::dispatch into overloaded functions Apparently, default parameters don't create another target for infering member-function-pointers. 2. Remove problematic template overloads in Thread constructor Issue is actually here ARMmbed/mbed-os#2395. The indirection in the nested callback templates prevented correct overload resolution and let to template-expansion errors. 3. Exposed break_ Allows threaded event queues to shutdown cleanly. With these changes, this code: EventLoop loop; loop.start(); loop.call(F); loop.stop(); Becomes: EventQueue queue; Thread thread; thread.start(&queue, &EventQueue::dispatch); queue.call(F); queue.break_(); thread.join(); Except now with 182 less lines to maintain
There is no elegant fix here:
|
@geky What do you think about this option compare to the rest? |
I agree, limiting the arguments to just the callback does seem like the best way forward, although it will be a decently big change from the current API. Would we mark the existing overloads as deprecated? At the very least deprecating the overloads should probably be a separate pr. |
/morph test |
Result: FAILUREYour command has finished executing! Here's what you wrote!
Outputmbed Build Number: 626 Test failed! |
/morph test |
Result: SUCCESSYour command has finished executing! Here's what you wrote!
Outputmbed Build Number: 628 All builds and test passed! |
LGTM? |
I'm happy with those changes but it is important to track the remaining work:
It would be interesting to track this before we forget about it. |
Would this be best tracked as an issue? |
Raised issue over here: #2490 Feel free to add anything I missed |
Note, I realized #2496 provides an alternative solution. Let me know any thoughts you have. |
I'm going to go ahead and merge this pr with #2496 to simplify things a bit and avoid confusion. |
…..48609ae 48609ae Merge branch 'release_internal' into release_external 62d8586 Ignore ns_monitor when receiving Ack (ARMmbed#2417) 3323f36 Add support for Ethernet RA dns configuration d8e7d40 Iotthd 4239 (ARMmbed#2414) b46f3c6 add empty function for ws_stack_info_get fc97980 Changed RADIUS shared secret length to 16-bit value f827ffc Added information API to Wi-SUN and border router 8f1f9d5 EDFE error handling update 51bf94e Fix adaptation interface unit tests (ARMmbed#2409) 0860b57 FHSS_WS: Fixed reading unicast remaining slots (ARMmbed#2408) 4d8c03b Border Router RADIUS client basic authentication functionality (ARMmbed#2406) fbfada9 Adaptation IF: Allocate fragmentation buffer only if needed (ARMmbed#2407) 66f1bff Added storing of PAN version to NVM on BR 89826ce Iotthd 4224 (ARMmbed#2403) 3fc1ae2 BR EUI-64 is now selected for 4WH using PMKID on 4WH Message 1 af8438e Timing tool traces (ARMmbed#2401) 7938795 Fixed new PD data request for check if EDFE exchange is active. 85ab8fd Extented Frame exchange support 86b1f27 Merge pull request ARMmbed#2399 from ARMmbed/IOTTHD-4220 fed69e0 Add missing test method to ws_empty_functions 6b58e26 Add EDFE mode to Socket API setsockopt 1283077 Test API to adjust 6LoWPAN fragmentation MTU size (ARMmbed#2398) e787874 Init MAC MTU size based on driver MTU size (ARMmbed#2397) bf8e89e Ignore neighbors using unsupported channel function (ARMmbed#2395) 1c263fd FHSS exclude channel usage from mask and Brazilian Domain support 841dcbe MAC: Configurable data whitening (ARMmbed#2393) 9a10d66 Fix global address detection (ARMmbed#2392) f27fe86 Corrected network name and PAN ID change on auth start bcce0ed Clarified border router routing table API description e4630a4 Wi-SUN interface now informs address changes as interface events 2174374 Fix error found by coverity (ARMmbed#2389) 843254a MPL: traces for transmit and receive message (ARMmbed#2387) git-subtree-dir: features/nanostack/sal-stack-nanostack git-subtree-split: 48609ae
…..48609ae 48609ae Merge branch 'release_internal' into release_external 62d8586 Ignore ns_monitor when receiving Ack (ARMmbed#2417) 3323f36 Add support for Ethernet RA dns configuration d8e7d40 Iotthd 4239 (ARMmbed#2414) b46f3c6 add empty function for ws_stack_info_get fc97980 Changed RADIUS shared secret length to 16-bit value f827ffc Added information API to Wi-SUN and border router 8f1f9d5 EDFE error handling update 51bf94e Fix adaptation interface unit tests (ARMmbed#2409) 0860b57 FHSS_WS: Fixed reading unicast remaining slots (ARMmbed#2408) 4d8c03b Border Router RADIUS client basic authentication functionality (ARMmbed#2406) fbfada9 Adaptation IF: Allocate fragmentation buffer only if needed (ARMmbed#2407) 66f1bff Added storing of PAN version to NVM on BR 89826ce Iotthd 4224 (ARMmbed#2403) 3fc1ae2 BR EUI-64 is now selected for 4WH using PMKID on 4WH Message 1 af8438e Timing tool traces (ARMmbed#2401) 7938795 Fixed new PD data request for check if EDFE exchange is active. 85ab8fd Extented Frame exchange support 86b1f27 Merge pull request ARMmbed#2399 from ARMmbed/IOTTHD-4220 fed69e0 Add missing test method to ws_empty_functions 6b58e26 Add EDFE mode to Socket API setsockopt 1283077 Test API to adjust 6LoWPAN fragmentation MTU size (ARMmbed#2398) e787874 Init MAC MTU size based on driver MTU size (ARMmbed#2397) bf8e89e Ignore neighbors using unsupported channel function (ARMmbed#2395) 1c263fd FHSS exclude channel usage from mask and Brazilian Domain support 841dcbe MAC: Configurable data whitening (ARMmbed#2393) 9a10d66 Fix global address detection (ARMmbed#2392) f27fe86 Corrected network name and PAN ID change on auth start bcce0ed Clarified border router routing table API description e4630a4 Wi-SUN interface now informs address changes as interface events 2174374 Fix error found by coverity (ARMmbed#2389) 843254a MPL: traces for transmit and receive message (ARMmbed#2387) git-subtree-dir: features/nanostack/sal-stack-nanostack git-subtree-split: 48609ae
…3fe574..48609ae 48609ae Merge branch 'release_internal' into release_external 62d8586 Ignore ns_monitor when receiving Ack (ARMmbed#2417) 3323f36 Add support for Ethernet RA dns configuration d8e7d40 Iotthd 4239 (ARMmbed#2414) b46f3c6 add empty function for ws_stack_info_get fc97980 Changed RADIUS shared secret length to 16-bit value f827ffc Added information API to Wi-SUN and border router 8f1f9d5 EDFE error handling update 51bf94e Fix adaptation interface unit tests (ARMmbed#2409) 0860b57 FHSS_WS: Fixed reading unicast remaining slots (ARMmbed#2408) 4d8c03b Border Router RADIUS client basic authentication functionality (ARMmbed#2406) fbfada9 Adaptation IF: Allocate fragmentation buffer only if needed (ARMmbed#2407) 66f1bff Added storing of PAN version to NVM on BR 89826ce Iotthd 4224 (ARMmbed#2403) 3fc1ae2 BR EUI-64 is now selected for 4WH using PMKID on 4WH Message 1 af8438e Timing tool traces (ARMmbed#2401) 7938795 Fixed new PD data request for check if EDFE exchange is active. 85ab8fd Extented Frame exchange support 86b1f27 Merge pull request ARMmbed#2399 from ARMmbed/IOTTHD-4220 fed69e0 Add missing test method to ws_empty_functions 6b58e26 Add EDFE mode to Socket API setsockopt 1283077 Test API to adjust 6LoWPAN fragmentation MTU size (ARMmbed#2398) e787874 Init MAC MTU size based on driver MTU size (ARMmbed#2397) bf8e89e Ignore neighbors using unsupported channel function (ARMmbed#2395) 1c263fd FHSS exclude channel usage from mask and Brazilian Domain support 841dcbe MAC: Configurable data whitening (ARMmbed#2393) 9a10d66 Fix global address detection (ARMmbed#2392) f27fe86 Corrected network name and PAN ID change on auth start bcce0ed Clarified border router routing table API description e4630a4 Wi-SUN interface now informs address changes as interface events 2174374 Fix error found by coverity (ARMmbed#2389) 843254a MPL: traces for transmit and receive message (ARMmbed#2387) git-subtree-dir: connectivity/nanostack/sal-stack-nanostack git-subtree-split: 48609ae
note: no API changes
Before this commit, the following pattern was suggested as a shortcut
for writing callback-based functions overloaded based on arguments:
Unfortunately, C++ did not fair well with this level of type-inference.
The initial problems were with variable-arity function. The M type would happily consume arguments during overload-resolution, only to fail during template-expansion. Removed from problematic functions, this bug was unfortunately easy to reintroduce (for example in the RtosTimer) since it is undectable without forcing the template to expand.
The latest problem is occuring during type-deduction of overloaded function pointers. The extra level of indirection with the templated-method parameter caused type-deduction to stop early, erroring with an ambiguity error. Even more unfortunate, this error is inconsistent, since some functions were unable to adopt the template-method pattern for the variable-arity issue mentioned earlier.
For example:
After running into these issues with this design pattern, the best path forward seems to be to simply remove the templated-method overloads. These have been replaced by the two explicit overloads for the existing callback arguments.
Note: Unless @pan- has a workaround up his sleeve, adding cv qualifiers to the callback overloads (see #2190) may result in a large number of overloads to perfectly match all of the callback's constructors. It's a discussion for when we reach that point, but it does raise the question of it we should continue this overloading style.
cc @0xc0170, @pan-