-
Notifications
You must be signed in to change notification settings - Fork 50
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
Using a std::function as a callback signal #57
Comments
I don't totally follow your original example about how it is done now. Also, I am not sure if it is the case, but you could add a callback function to a transition execution, have a look to "react_with_action": Another mechanism we have is a "labeled OnExit" callback. You could define some exit code if some specific transition was executed. for example, something like:
|
I was mostly curious about making the callback registration with
I'm wondering if there's a way to do something like this instead:
I tried doing this, but ran into compilation problems and I couldn't tell if this was a Boost.Signals2 limitation or not. This is purely a stylistic question, rather than functional. I only ask since we have a few 1-line callbacks which would be nice to replace with a lambda or |
I like the idea of lambda expressions, I am a fan of them. But this simple example is not as simple as it may look and there his a reason why right now the syntax is like that. Let me ask you first a question:
SMACC implements an automatic unsubscription mechanism for callbacks (using the object SmaccSignal). So, a Smaccsignal is something more than a boostSignal. The SMACC stateMachine contains a list of all signal connections and disconnect them when it is required. Now, I would love to hear more about your thoughts taking all this information into account. I am not totally happy with the implementation of SmaccSignal, I think they should be easier to use. However, I also think this mechanism for auto-management of signal connections is important and should be kept. |
That's a fair point and I've not though about it too much. I agree, SMACC's automatic signal management features are really one of its strong points. As far as I know, lambda and
This does seem suspiciously simple though, so curious to hear what I'm missing |
I am afraid, it is not as easy as it may look. It would be great if you found a solution, but I do not see there is a solution yet. The actual challenge is not making our code compile using a lambda, that is totally possible. In fact, that option already existed for some time but it was removed. Lets talk about the issue with an example. Lets say we have a client (long-life object) such as the Nav2ZClient. Now, lets say we want to subscribe to some of these signals from some short-life object such as an state or a clientbehavior. Actually CbNavigateForward wants to subscribe to Nav2ZClient's signals to post their own events.
The lambda function is owned by the nav2zclient, a long-term object. (it is not owned by the client behavior) question: What would it happen if that onSuccess signal is raised after we left the state because some transition was triggered? But the lambda would be invoked. We would get here a segmentation fault on this->fooCb(). This is what I see about using lambdas. Does that make sense for you? Maybe I am the one that is missing something about your view. |
@pabloinigoblasco I've had some time to look at this again and reviving this thread from the dead (hope that's ok :) ). I was wondering if you could explain how SmaccSignals work and how they're different to boost::signals2 signals? I see that SmaccSignals are based off of boost::signals2, so was hoping you could clear up the difference. I think the issue is that the signals aren't really attached to a specific object's lifetime. They're lifetimes are manually managed and are destroyed during state transitions here, but if (for whatever reason) a client behavior goes out of scope before a transition occurs, a segfault will also take place. Would it be possible to make this lifetime attachment using something like std::bind where the signals are created here? Would the caller be informed that the object is out of scope which could then trigger some kind of deletion? Also, would it make sense to look at using signal2's track() method to automatically manage signals' lifetimes? This would make tracking the signals' lifetimes truly automatic, but would require considerable work to implement, because the objects will need to be encapsulated inside shared_ptr objects to be compatible with track. However, there might be additional benefits to this and using smart pointers more broadly (I mentioned a few in #86 (comment)). Curious to hear your thoughts? |
Hello @yassiezar. I think is very good to analyze together internal code. It is a way of documenting and making the core stronger. So thanks.
The short-lifetime types we have are: states, client-behaviors, state-reactors and event generators. The scope of all these types is controlled by internal SMACC code so this disconnection happens always before they are destroyed. Because of that "client behavior goes out of scope before a transition occurs" cannot happen. (unless there is a bug). Maybe I am missing something? if we are talking about objects with more uncertain lifetimes, it may be worthwhile to focus on components or clients instead. Although, as of now, SMACC signals are designed to exist throughout the lifetime of the entire application, perhaps we should consider the possibility that this may not always be the case.
I am open to introducing new changes to the syntax of SMACC signals. Initially, I had planned to create an extension of boost::signals2:signal that would be capable of handling the lifetime of objects and would use the same syntax. However, upon attempting this, I encountered several problems that ultimately led me to switch to the current syntax we are using. Now, the question arises as to what would be the impact of transitioning from the current SMACC signals and pointers to the new version that uses shared_ptrs, which would require changing examples, libraries, and code. I believe that such a transition would be a costly development effort, and therefore, I suggest that before taking any action, we should experiment with some motivating use cases and play with some code chunks that showed the benefits of the new final syntax. @pabloinigoblasco I found a way to roll back my previous comment so I copied your response here. Feel free to post it again if you want |
When I started using SMACC, I thought that the signal connection lifetimes were attached to the parent object's lifetime. The robust attachment/detachment performance during high-frequency transitions and the fact you pass the parent's It looks from the surface then that the main thing that prevents us using an anonymous function instead of a functor for the signal callbacks are that there are no objects to reference when you're doing the manual disconnections during state transitions.
Totally agreed, the benefits of transitioning to a new memory management approach needs to justify the development effort required. I've mentioned a couple of benefits of moving to smart pointers already, but I'm sure you'll have better insight on the problem. I guess the question is whether there's interest from your and the other core maintainers' side to see a transition to smart pointers take place? I'd like to play around with a making minimum viable example when I have some spare time, but your input would of course be hugely helpful. |
At the moment, message callbacks are handled by defining a function to receive a message and create a boost signal by passing said function and its attached parent object. Is there any way to define the callback as a std::function variable instead and register it as a callback with the signal manager instead? This would make it a bit less verbose to write a simple 1-line functions that fires a state transition event, for example.
┆Issue is synchronized with this Jira Task by Unito
┆Link To Issue: https://robosoft-ai.atlassian.net/browse/SMACC1-3
The text was updated successfully, but these errors were encountered: