Jump to content
  • Advertisement
Sign in to follow this  
Munchkin9

C# To Callback or not to callback

Recommended Posts

I've got a problem and I'm not happy with the solution I found, looking for input.

Commands, which serve as passable functions are stored into a queue that gets pulled from on regular intervals. Then they are stored in an EnquedCommand object and placed into a different queue. EnquedCommand contains some info such as where the command is being run from. The second queue is also pulled from on regular intervals. The objects that submit the commands and each Queue are kept separate so they have no easy means of communication. This has worked fine so far.

The problem is I now have a command that is supposed to have the original object that enqued it do something when that command is run in the final queue. But it has no easy means of knowing when that happens.

The solution I found is to embed a callback parameter into EnquedCommand and have that passed through the queues so that the callback is called when the command is run. What I don't like about the solution is that this requires a fair bit of refactoring and, so far, this is the only command that needs one. Seems like overkill.

Are there any other solutions anyone can think of?

Share this post


Link to post
Share on other sites
Advertisement

callback seems fine for this.

or just in the command that needs it, have an additional member variable such as m_command_has_executed with a get_has_command_executed() member function.  Have the original object that created the command maintain a reference to the command.  On the next tick when the object runs its update() method, have it check the last_enqueued_command->get_has_command_executed() to see if it already ran.  but don't see how that is really any much better than a callback function.  just another way.

Share this post


Link to post
Share on other sites

Seems like there are some other potential concerns, such as object lifetimes. Some languages and tools are better suited at this than others, but there are important details like making sure the objects involved are all still valid when commands are run.

I've worked with container-style systems where objects in the container can have their function called at specific future points in time, such as before/after processing, before/after rendering, before/after physics. It is more special purpose than you described, but has the benefit of letting the container verify the object is still alive before calling the function.

I've also seen many event bus systems allow for delayed events to be broadcast. A system can register an event listener and fire a timed event.  If the target object is still alive the object's listener can respond, if the object has died it will have been de-registered as a listener so no problems from running a callback on dead objects.

For the specific problem you're facing a message bus sounds ideal.  The original object can indicate it needs an event with a specific unique ID.  The system can listen for the event, and if the unique ID matches it can do the work it had delayed. The system may need other protections, such as killing off long-overdue tasks, but the message bus pattern solves all kinds of inter-object communications issues.

Share this post


Link to post
Share on other sites
On 12/24/2017 at 9:10 AM, Munchkin9 said:

The solution I found is to embed a callback parameter into EnquedCommand and have that passed through the queues so that the callback is called when the command is run. What I don't like about the solution is that this requires a fair bit of refactoring

Commands are functions, right?  If they already perform work then why does anything need to be refactored?  Perform the callback within the normal work of the command's function, or wrap the command with a command which calls the original command THEN the callback, if that makes more sense.  Imagine this pattern, but adapted to whatever additional complexities you require (IPC, RPC, etc).

Action WrapAction(Action command, Action callback)
{
  return () =>
  {
    command();
    callback();
  };
}

If you're dealing with IPC then you will definitely need some way of handling responses and completion which can deal with the callback.  It's not overkill.  If you're NOT dealing with IPC then do you really need all those intermediate objects and queues?

Edited by Nypyren

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!