Running with Code Like with scissors, only more dangerous

21Apr/080

The Difficulties of Using a Multicast Event-based API

I’ve made allusions to my current project several times, and while I can’t discuss it with specifics, but I’m working with hardware; part of the device is an armature that extends to receive a piece of equipment from the user, and then it will once again extend to re-dispense the object at the conclusion of its task.  The armature controller hardware is strictly asynchronous, and as such, I decided initially to write it with asynchronous callbacks.  It’s fairly straightfoward to have a method called "Extend" and an event called "Extended."  Once I was able to establish this API, I thought it would be fairly straightforward for the rest of the development team to move forward.

I thought incorrectly.

As .NET developers, I think we’re conditioned from the time that we open the IDE to make sure that event handlers are wired up throughout the lifetime of the application.  In fact, both C# and Visual Basic make it so easy for multiple methods to handle events, that it’s sometimes silly not to.  C# and Visual Basic event handling syntax is syntactical sugar of the Observer pattern.  And why shouldn’t it be?  For probably 99.9% of the applications out there, it’s great.

Still, the current project has me a bit miffed.

Consider that there are two instances in which the arm needs to be extended: one to accept the user’s item, and the other to re-dispense it.  Dispensing the item happens automatically when the arm is flipped upside-down and then extended.  So, I can track state:

private void Arm_Extended(object sender, EventArgs e)
{
    if (receivingItem)
    {
        // wait for button press
    }
    else // if dispensing item
    {
        Arm.Retract();
    }
}

Doesn’t this seem kludgy to you?  If not here, then consider that within a single class I potentially have six objects reporting asynchronous task results that may need to be handled differently depending on the state of the machine.

Unfortunately, the alternative method seems just as kludgy:

private void ArmExtendedForUserPrompt(object sender, EventArgs e)
{
    Arm.Extended -= handlerForArmExtendingForPrompt;
    Controller.PromptUserForItem();
}

private void ArmExtendedForDispensing(object sender, EventArgs e)
{
    Arm.Retracted += handlerForArmRetractAfterDispenseCompleted;
    Arm.Extended -= handlerForArmExtendedForDispensing;
    Arm.Retract();
}

The primary reason I’ve chosen the latter approach is that stack traces have a bit more meaning to me.  That’s it.  I guess it’s arguable that I don’t need to manage umpteen state flags.  ( As a side note, I’ve just learned that the spell checker in Windows Live Writer considers "umpteen" to not be a spelling error ).  But the truth is that, state flags or function pointers, I’m still managing state.

It might have been more appropriate to handle asynchronous callbacks as parameters to functions:

public void Extend(object state, AsyncCallback callback) { ...

This is tricky, too; it means needing to manage an additional two variables per asynchronous call.  For an object that might support multiple concurrent asynchronous operations, that can become a nightmare of complexity management.

I don’t have the right answer for this.  But it’s definitely something to watch out for in the future.

Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

ERROR: si-captcha.php plugin says GD image support not detected in PHP!

Contact your web host and ask them why GD image support is not enabled for PHP.

ERROR: si-captcha.php plugin says imagepng function not detected in PHP!

Contact your web host and ask them why imagepng function is not enabled for PHP.

No trackbacks yet.