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

Remove problematic templated overloads on callback-based functions #2395

Closed
wants to merge 1 commit into from

Conversation

geky
Copy link
Contributor

@geky geky commented Aug 8, 2016

note: no API changes

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.

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-

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.
geky added a commit to ARMmbed/mbed-events that referenced this pull request Aug 9, 2016
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
geky added a commit to ARMmbed/mbed-events that referenced this pull request Aug 9, 2016
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
@pan-
Copy link
Member

pan- commented Aug 9, 2016

There is no elegant fix here:

  • Function pointer overload can be cast at user side
  • Just accept callback as the function parameter, it force the user to write ticker.attach(Callback<void()>(&t, &Thing::doit), 1.0f /* delay */). For non overladed function member it is even possible to provide an equivalent to bind: ticker.attach(make_callback(&t, &Thing::doit), 1.0f). This is I believe the best solution once, it will always work with everything when member function cv qualifiers will be correctly handled by the Callback class.
  • Provide any overload possible, it doesn't work for cv member functions at this stage and increase the maintenance effort while easing the usage.

@0xc0170
Copy link
Contributor

0xc0170 commented Aug 9, 2016

Just accept callback as the function parameter

@geky What do you think about this option compare to the rest?

@geky geky changed the title Remov problematic templated overloads on callback-based functions Remove problematic templated overloads on callback-based functions Aug 9, 2016
@geky
Copy link
Contributor Author

geky commented Aug 9, 2016

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.

@geky
Copy link
Contributor Author

geky commented Aug 10, 2016

/morph test

@mbed-bot
Copy link

Result: FAILURE

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

/morph test

Output

mbed Build Number: 626

Test failed!

@geky
Copy link
Contributor Author

geky commented Aug 10, 2016

/morph test

@mbed-bot
Copy link

Result: SUCCESS

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

/morph test

Output

mbed Build Number: 628

All builds and test passed!

@geky
Copy link
Contributor Author

geky commented Aug 17, 2016

LGTM?

@pan-
Copy link
Member

pan- commented Aug 18, 2016

I'm happy with those changes but it is important to track the remaining work:

I agree, limiting the arguments to just the callback does seem like the best way forward..

It would be interesting to track this before we forget about it.

@geky
Copy link
Contributor Author

geky commented Aug 18, 2016

Would this be best tracked as an issue?

@geky
Copy link
Contributor Author

geky commented Aug 18, 2016

Raised issue over here: #2490

Feel free to add anything I missed

@geky
Copy link
Contributor Author

geky commented Aug 18, 2016

Note, I realized #2496 provides an alternative solution. Let me know any thoughts you have.

@geky
Copy link
Contributor Author

geky commented Aug 19, 2016

I'm going to go ahead and merge this pr with #2496 to simplify things a bit and avoid confusion.

@geky geky closed this Aug 19, 2016
artokin pushed a commit to artokin/mbed-os that referenced this pull request Aug 17, 2020
…..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
artokin pushed a commit to artokin/mbed-os that referenced this pull request Aug 18, 2020
…..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
artokin pushed a commit to artokin/mbed-os that referenced this pull request Aug 21, 2020
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants