mapSingleton vs. mapValue

Richard Willis's Avatar

Richard Willis

14 Dec, 2009 04:59 PM

using mapSingleton I have a working example of proxy injection. in my AppContext:

injector.mapSingleton(UserProxy);

then, in my StartUpCommand:

public class StartUpCommand extends Command
{

[Inject] public var userProxy:UserProxy;

override public function execute ():void
{
    trace('StartUpCommand', userProxy);
}

}

all working fine, great. however, looking at this:

http://knowledge.robotlegs.org/faqs/framework-core/injection-mappin...

i understand that i can change my AppContext code to this to achieve the same result:

var userProxy:UserProxy = new UserProxy();
injector.mapValue(StartUpCommand, userProxy);

however if I do that i get the following error:

Error: Injector is missing a rule to handle injection into target [object StartUpCommand]. Target dependency: com.client.appname.model::UserProxy

woe is me! what gives?

  1. Support Staff 1 Posted by Joel Hooks on 14 Dec, 2009 05:02 PM

    Joel Hooks's Avatar

    On Dec 14, 2009, at 10:59 AM, Richard Willis wrote:

    > var userProxy:UserProxy = new UserProxy();
    > injector.mapValue(StartUpCommand, userProxy);
    >
    > however if I do that i get the following error:
    >
    > Error: Injector is missing a rule to handle injection into target [object StartUpCommand]. Target dependency: com.client.appname.model::UserProxy

    var userProxy:UserProxy = new UserProxy();
    injector.mapValue(UserProxy, userProxy);

    You are mapping the value of a UserProxy class with a specific instance, not mapping the value to BE injected in a specific class.

  2. Support Staff 2 Posted by Shaun Smith on 14 Dec, 2009 07:52 PM

    Shaun Smith's Avatar

    Indeed, the way you were doing it initially seems more appropriate, ie:

    injector.mapSingleton(UserProxy);
    

    Unless you have a reason to eagerly instantiate the proxy, in which case:

    var userProxy:UserProxy = new UserProxy();
    injector.mapValue(UserProxy, userProxy);
    

    However, it's usually better to let the framework instantiate the class lazily (as it does with mapSingleton), rather than eagerly (as with mapValue).

  3. 3 Posted by Richard Willis on 15 Dec, 2009 01:37 PM

    Richard Willis's Avatar

    thanks guys.

    why would you consider mapSingleton's lazy instans. to be better shaun? i realise it doesn't actually create a singleton, but anything with that word in it tends to make me a bit nervous.plus my understanding is that mapSingleton just injects its given class willy-nilly around the architecture blindly. isn't that a bit of an unnecessary overhead?

    i'm new to dep. inj. (just started this week) so if sorry if these come across as idiotic newbie questions. just tryin to learn.

    :)

  4. Support Staff 4 Posted by Till Schneidere... on 15 Dec, 2009 02:00 PM

    Till Schneidereit's Avatar

    Hey Richard,

    > why would you consider mapSingleton's lazy instans. to be better shaun? i realise it doesn't actually create a singleton, but anything with that word in it tends to make me a bit nervous.

    In my opinion, mapSingleton has three advantages over mapValue:
    - The fact that it lazily creates its instance means that the instance
    is created exactly if and when it is needed, possibly reducing
    initialization overhead in cases where it is used for seldomly
    accessed functionality
    - It clearly communicates the intent: The developer wants exactly one
    shared instance of this class to be used for every request made
    - It simply reduces what you have to type and automates priming the
    singleton itself with dependencies by instantiating it internally and
    immediately injecting into it

    As Shaun said some time ago, Singletons with a big "S" are the
    original anti-pattern and should be avoided at all costs. On the other
    hand, there's nothing wrong with explicitly stating that you want each
    request for a certain type (and possibly a certain name) to be
    fulfilled with the same instance of a class. And that's exactly what
    singletons with a small "s" are for.

    > plus my understanding is that mapSingleton just injects its given class willy-nilly around the architecture blindly. isn't that a bit of an unnecessary overhead?

    I'm not sure what you mean by that, maybe you can elaborate a bit?
    After the instance has been created at first request, value and
    singleton mappings should be pretty much identical in behavior and
    overhead.

    > i'm new to dep. inj. (just started this week) so if sorry if these come across as idiotic newbie questions. just tryin to learn.

    No worries. Feel free to check the knowledge database and ask questions.

    cheers,
    till

  5. 5 Posted by Tyler Wright on 15 Dec, 2009 07:22 PM

    Tyler Wright's Avatar

    However, it's usually better to let the framework instantiate the class lazily (as it does > with mapSingleton), rather than eagerly (as with mapValue).

    It's usually better to say why it's better, rather than just saying that it is. :)

    The only functional difference I see, as Till pointed out, is that mapSingleton won't create the instance until it's needed, possibly reducing initialization time and saving some runtime memory. From project's I've worked on this seems rare and the savings would be unnoticeable.

    Personally I like mapValue best (at least today I do), considering that the Injector's singleton is really only single to itself (not system-wide) and so not really a Singleton, which is why we feel better using it.

    Good discussion, thanks!

  6. 6 Posted by Tim Oxley on 16 Dec, 2009 03:44 AM

    Tim Oxley's Avatar

    Perhaps the problem is the big S. mapSingleton should be renamed mapsingleton ;)

  7. Support Staff 7 Posted by Shaun Smith on 16 Dec, 2009 05:48 PM

    Shaun Smith's Avatar

    @Tim: Haha! Believe it or not, I had actually considered that!

    @Tyler:

    One of the benefits of DI is that client code doesn't have to know "how" to construct the objects/collaborators/dependencies that it needs to get it's job done. The task of constructing such an object can be left to the container.

    The benefits of Lazy vs Eager aside, using mapValue requires that you construct said object yourself. If the constructor of the object changes you will need to change the code that constructs it. The container, on the other hand, would most likely be able to figure out how to construct the new object without any changes to your code.

    Also, manually constructing objects that rely on setter injection is error prone: you might forget to set the appropriate dependencies after construction. Leaving construction to the container will safe guard against that.

    The only time that I use mapValue is when I need to put an object into the container that already exists. For everything else, I leave it up to the container to build my objects for me.

    Finally (and very subjectively), using mapValue makes me feel like I'm using the Service Locator / Registry pattern - granted, an IoC container IS a registry of sorts - I just don't like it!

  8. 8 Posted by Tyler Wright on 17 Dec, 2009 03:33 AM

    Tyler Wright's Avatar

    I see your point. DI isn't my primary workflow for object creation - I
    assumed that each object to map wouldn't often be injected itself, otherwise
    you have to start worrying about the order of your mappings. But I can see
    that I would want a Controller injected into, and then to be provided via
    injection into other objects.

    So mapSingleton does the following, except lazily: mapValue(Type,
    instantiate(MyType));

    re: registry - everything needs a home, a registry can be a beautiful
    organization of data and configuration, making a system easy to update and
    extend (as we see from RL Injector/Context). It's only ugly when it becomes
    a global trough for all the table scraps. :)

  9. Till Schneidereit closed this discussion on 02 Mar, 2010 12:55 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