Injector.injectInto Conundrum and Object Pooling Optimization

ZackPierce's Avatar

ZackPierce

28 Oct, 2010 05:06 AM

I'm doing an investigation into optimizing Robotlegs by (optionally) using object pools to re-use Mediator and Command instances.

The general idea of object-pooling is to reduce the overhead of repeated object-instantiation, at the cost of some further book-keeping and storage. This technique might be appropriate for mid-to-large applications with multiple-instance view components mediated by class, or for applications with commands re-executed at high frequency.

In practice, this would mean storing mediators after they go out of use, grabbing an old instance if possible, and injecting freshly mapped dependencies (read: the new view component) into the old mediator.

The problem I hit is that the SwiftSuspenders Injector class keeps track of all objects that it has ever injected into (directly or via instantiate calls), and refuses to re-inject into those objects. I'm sure this refusal was planned as a short-circuit to prevent re-walking and re-satisfying dependency trees at some point, but being unable to re-inject into an object ever seems a bit rigid.

Perhaps the IInjector.injectInto method signature could be expanded to include an optional forcing parameter that overrides any internal tracking preventing repeat injection?

function injectInto(target:Object, overrideExistingInjectedObjects:Boolean = false):void;

Even if my original purpose, playing with object pooling in Robotlegs, is ultimately a dead end, I wonder if this API change has merit in terms of generally improving the flexibility of the Robotlegs IInjector?

  1. Support Staff 1 Posted by Shaun Smith on 28 Oct, 2010 05:17 PM

    Shaun Smith's Avatar

    Hi Zack,

    I'm sure this refusal was planned as a short-circuit to prevent re-walking and re-satisfying dependency trees...

    That's exactly it. Have you had a look through the SwiftSuspenders source? Perhaps there is an easy way to remove objects from the dictionary?

    I'm not sure I like the Boolean param in the method signature... will have to ponder it some more.

    Nevertheless, I like the idea, and am interested in seeing your pooling approach.. do you have any code for that online? Perhaps we could combine efforts - I've started down a similar path with a library/extension called "Oil":

    http://github.com/darscan/robotlegs-extensions-Oil

    My object pool is super rudimentary, but works ok for now:

    http://github.com/darscan/robotlegs-extensions-Oil/blob/master/src/...

    The pool was initially intended to recycle item/data renderers; I hadn't even considered pooling mediators and commands. I think an event-less, object-pooled RL framework impl would be pretty cool.

  2. 2 Posted by ZackPierce on 29 Oct, 2010 12:06 AM

    ZackPierce's Avatar

    I've looked in the SwiftSuspenders source, and it seems quite accessible for modifications. No code to share yet, was trying to decide the best place for it -- forking Oil seems like a fun and appropriate place to get going tonight.

  3. Support Staff 3 Posted by Shaun Smith on 29 Oct, 2010 01:35 AM

    Shaun Smith's Avatar

    Cool. Have just pushed some updates, docs and a demo thing. Kinda freestyling it, so feel free to go wild.

  4. 4 Posted by ZackPierce on 29 Oct, 2010 05:43 AM

    ZackPierce's Avatar

    I've got command and mediator instance reuse working in my fork of Oil:

    http://github.com/ZackPierce/robotlegs-extensions-Oil

    Which in turn requires my slightly-tweaked forks of Robotlegs and SwiftSuspenders.
    http://github.com/ZackPierce/robotlegs-framework
    http://github.com/ZackPierce/SwiftSuspenders

    These should all differ from the upstream only with regards to adding support for re-injection, and thus object recycling.

    The solution I reached is not to change the IInjector interface, but to modify the SwiftSuspenders Injector to have the optional capability for forced re-injection.

    The old SwiftSuspenders Injector.injectInto was renamed injectIntoObject.The SwiftSuspendersInjector class has a public injectInto method that wraps a call like super.injectIntoObject(object, true);

    This way, we only use forced injection if one explicitly calls injectInto (rather than indirectly through IInjector.instantiate) at the Robotlegs level.

    This is based on the assumption that if you call IInjector.injectInto on an object, you always want your latest mappings to be reflected in what the object holds at the end of the call, and not worry about any previous state-manipulations or injection calls related to that object.

    "I don't care how it got here, but it damn well better have all of its dependencies met after I call injectInto"

    Test cases were added to Oil as well.

  5. Support Staff 5 Posted by Shaun Smith on 29 Oct, 2010 10:46 AM

    Shaun Smith's Avatar

    Nice one! I'm away for the weekend, but will check it all out next week. Cheers!

  6. Support Staff 6 Posted by Shaun Smith on 02 Nov, 2010 12:33 AM

    Shaun Smith's Avatar

    Hi Zack,

    I haven't had much time to look through your code (moving house, starting new job), but I did spot a couple of things:

    DRY: RecyclingCommand/MediatorMap completely re-implement the RL base classes. I realize that the hooks needed to avoid this are missing from RL at present, but we can easily add them to RL as they won't incur any behavioral or API changes. I'm probably not explaining myself well... think of it this way: how can we make the Recycling*Maps as short as possible, and avoid duplicating a single line of code from the RL base classes?

    Also, I think they should be called PooledCommandMap and PooledMediatorMap. And they should probably live in an mvcs package (as they are modeled on the RL mvcs framework).

    I've pushed some updates (Promise processing) in the meantime. Will try get round to adding those RL hooks some time this week (or next), and updating your maps.

  7. 7 Posted by ZackPierce on 09 Nov, 2010 07:19 PM

    ZackPierce's Avatar

    Thanks for the feedback, I'll jump back into this when my day-job workload eases up a bit.

  8. 8 Posted by vijay shan on 21 Dec, 2010 08:38 PM

    vijay shan's Avatar

    I ran into this problem today. had a solution that worked within my app. Shaun, would like to see how you would address this at the framework level. The boolean seems to be a pretty straight forward approach, Is this something you are actively looking at?

  9. Stray closed this discussion on 11 Feb, 2011 10:55 PM.

  10. ZackPierce re-opened this discussion on 05 May, 2011 05:12 AM

  11. 9 Posted by ZackPierce on 05 May, 2011 05:12 AM

    ZackPierce's Avatar

    Super-late for a reply, but I thought I'd follow up for the sake of closure.

    Ultimately, I abandoned development on the recycling/object-pooling oriented approach to the mediator and command maps because the additional overhead of cleaning up objects for re-use imposed a more considerable cognitive load on development than I originally anticipated.

    While ideally, most mediators should be nearly stateless, in practice, I found that consistently doing the book-keeping of clearing out all intermediate data was an extra dev-stress with pretty minimal performance benefits. It turns out that it's not technically hard to add a bunch of property = null; statements, but it is troublesome to determine which properties are truly disposable or a cross-injection usage risk for every single mediator class in a nontrivial codebase and remember to clean them all.

  12. Support Staff 10 Posted by Stray on 05 May, 2011 12:48 PM

    Stray's Avatar

    Thanks Zack,

    I completely agree with your math:

    (developer-headaches = opportunities to make mistakes = broken code) < faster code

    It's great to get a follow up though. I agree that mediators should be stateless, but it's best not to hand out more rope :)

    Stray

  13. Stray closed this discussion on 05 May, 2011 12:48 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac