Dependency Injection / Dependency Management (part 1)

I'm not an expert when it comes to dependency injection, but I do know a little. My team uses Unity in one of its projects, so I have some exposure. Recently, I started work on a project (hoping to eventually release it as OSS) on a Dependency Injection (like) / Dependency Management framework for the client (that is, written in Javascript). Since it was (is) a fun project for me, I thought I might blog about some of the more interesting parts of what I've done. Dependency Resolution: One of the key parts of Dependency Injection is dependency resolution. That is, if I need an instance of something, say, a Foo, and if creating a Foo requires an instance of say, a Bar, then my DI framework ought to resolve the Bar for me on its way towards creating my Foo.
var registration =
{
   Foo: { className: 'Stephen.Stchur.Foo', params: [ 'Bar' ] },
   Bar: { className: 'Stephen.Stchur.Bar' }
}

// obviously, code for Container, not show here (yet)
var c = new Container(registration);
var f = c.instance('Foo')// container "knows" Foo needs Bar; it takes care of it for us
So what I'm focusing on in this blog post is the comment above: "container 'knows' Foo need Bar; it takes care of it for us. In a future post, I'll be talking more about the management part (involving not only resolving types on demand, but also downloading dependencies and groups of dependencies prior to resolution). But for now, let's just assume that all dependencies needed to create anything/everything have already been preloaded. So how does the container know that Foo needs a Bar? Well, it's not too hard to figure out if you look at the registration. It's just a dictionary of key/value pairs, where the value is a simple object literal containing a couple properties:
  1. className - required, the fully qualified name of the thing that the container will eventually be creating instances of
  2. params - optional, an array of string keys that map to other values in the registration dictionary
Container knows that Foo needs a Bar because that was explicitly spelled out in the registration when we defined:
Foo: { className: 'Stephen.Stchur.Foo', params: [ 'Bar' ] }
The params array tells the container everything it needs to know. So what does the code that actually implements this type resolution look like? Glad you asked. Code below, explanation to follow:
function Container(reg)
{
    function instance(factoryName)
    {
        var params = reg[factoryName].params;
        var i = params.length;    
        while (i--)
        {
            var f = reg[params[i]];
            if (f)
            {
                params[i] = instance(params[i]);
            }
        }

        return create(reg[factoryName].className, params)
    }
    this.instance = instance;

    function create(type, params)
    {
        var constructor = new Function('return ' + type)();
        var inst = new constructor();
        inst.init && inst.init.apply(inst, params);
        return inst;
    }
}

var c = new Container(registration);
var f = c.instance('Foo');
Now this is not actually the code used in the project I'm working on. It's actually rather different, but this will suffice for now. One thing to note is that I'm really not performing any sort of safety checks here. If you ask the container for an instance of something that hasn't been registered, it will not fail gracefully (and it really should). But that's an easy change and not really the focus here. There isn't a ton code that requires explanation here, except for a couple pieces. The first piece that I suspect will raise some eyebrows is:
var constructor = new Function('return ' + type)();
Now let me say right off the bat that I'm not claiming this is the best way to do it (certainly it's not the only way). Essentially, this is just a confusing way of doing:
var constructor = eval(type);
So why not just do that? Well, I'm not saying you can't, but a lot of people have a hard-line stance against using eval. Also, in some browsers, eval was much slower than using new Function(..). However, in other browsers, eval was faster (sometime nominally, sometimes significantly). Finally, there is another option in this case: you can split the type string on the dot, and actually attempt to access the parts as properties. It would ultimately translate to something like:
var constructor = window['Stephen']['Stchur']['Foo];
Of course, you wouldn't hard code it like that, you'd split the string and loop, but I trust you get the idea. For simple cases, this actually turns out to be quite fast, so it's something to consider. But also worth considering is that fact that, for small numbers of repeated executions, it matters very little which method you choose. And if you cache the resolved constructor once you get it, it matters even less. Anyway, I used new Function(..) in this post, because I think it's an interesting way to accomplish the task (not necessarily the best, but chances are you haven't seen it before, so you learned something, and that's what this blog is all about -- spreading knowledge and learning). If you're unfamiliar with Function (capital F) in Javascript, allow me to explain. Function in Javascript is a constructor that takes a string and returns you a function whose logic is whatever string-code you passed into it. For example:
var sayHello = new Function('alert("hello there");');
sayHello();       // alerts "hello there"
It's not too hard then to see how we've leveraged Function in our case. We created a function whose job it is to return a reference to function named, type. That is, if type = "Foo" then this code:
var constructor = new Function('return ' + type)
Will result in the variable constructor, pointing to the function, Foo (so it essentially is Foo). Another way of thinking about it is that the implementation of the function we've create is:
return Foo;
And when you execute that function, what you get back is a reference to the function Foo, which is the constructor you care about. Great! Now what? Well, now we should invoke the constructor. Unfortunately, things fall a part a little bit here (but only a little). There isn't really a great way to invoke a constructor with the new keyword and at the same time pass in an array of params to be used as the individual arguments to that constructor. More clever Javascript Ninjas will give you creative solutions. You can create an empty object, and then call .apply on the constructor, passing in the object you created as the this object and the items in whatever array you pass in will becomes the individual arguments to the constructor. This however, won't result in an object that actually is an instance of your constructor.
function Cat(name, age)
{
    this.description = 'furry';
    this.name = name;
    this.age = age;
}
var c = {};
Cat.apply(c, [ 'Garfield', 10 ]);
c instanceof Cat; // false 🙁
You can carry this further though. You can set the native prototype of your c object to be Cat's prototype:

var c = {};
c.__proto__ = Cat.prototype;
c instanceof Cat; // true 🙂
However, support for __proto__ is not so good in several older versions of a certain, still-fairly-popular-but-I-have-no-idea-why browser (I'm a Firefox guy myself). It's worth pointing out here that your temptation to try c.prototype = Cat.prototype will not work, but I'm not going to get into why. This isn't a post about prototype in Javascript. If you care to, you could iterate Cat's prototype and manually copy over all the properties. Then your object would satisfy as a Cat if you're okay with duck typing. But it still wouldn't actually be a Cat. Well, if you're only targeting browsers that support __proto__, then that's an option. If you don't care about your object actually being a true instance of the thing you're creating, then you can use .apply and copy over the prototype. Or, if you have some magic pixie dust that I don't have, then I suppose that's an option too (please share). Short of any of those things, your other option is to mandate some sort of a convention. Two conventions come to mind that are simply and work well.
  1. Mandate that all constructors be able to successfully execute, parameterless. And then automatically call (if it exists) some special initialization function (I like .init) that take all the params that really matter.
  2. Mandate that all constructors take only a single param - an array of values needed to construct the instance.
I chose option 1 for the sample code in this post. I like it better than option 2 because I have a Chocolate Lab named Guinness (that didn't make any sense). Moving on... With the instantiation out of the way, the only remaining bit of code might be the resolution of the params. First we grab a reference to the array of params, as defined by this factory's definition in the registration:
var params = reg[factoryName].params;
We then loop through it (backwards, because that's how I roll), and pull out each value, assigning it to the variable, f. We assume that f points to a valid, registered, factory. If not, we leave the value alone (this isn't particular useful right now, but in a future blog post, you'll see the code reworked a bit so that the .instance function can accept arbitrary values to be used as other arguments in constructing your object). Now if f does point to a valid, registered factory, then we go ahead and resolve it. Resursively. By calling .instanace again. This is important, in case of the params, are factories that take other params that are factories. Once we've resolved a param though, we can actually just have the result "take over" what was in the original params array at the index originally.
params[i] = instance(params[i]);
In this way, the right value will be in the right place in the params array when it finally gets plumbed through to the call to inst.init.apply(inst, params) Makes perfect sense right? Honestly, I think it's harder to speak/write about than it is to just understand. It's not super complicated. It will get more complicated though. But that's for a future blog post. In the mean time, here's a full, copy/pastable bit of code that actually works.
var Stephen =
{
    Stchur:
    {
        Foo: function()
        {
            this.desc = 'foo!';
        },

        Bar: function()
        {
            this.desc = 'bar!';
            this.init = function(f) { this.myFoo = f; };
        },

        Baz: function()
        {
            this.desc = 'baz!';
            this.init = function(f, b)
            {
                this.myFoo = f;
                this.myBar = b;
            };
        }
    }
};

var registration =
{
    Foo: { className: 'Stephen.Stchur.Foo' },
    Bar: { className: 'Stephen.Stchur.Bar', params: ['Foo'] },
    Baz: { className: 'Stephen.Stchur.Baz', params: ['Foo','Bar'] }
};

function Container(reg)
{
    function instance(factoryName)
    {
        var params = reg[factoryName].params || [];
        var i = params.length;    
        while (i--)
        {
            var f = reg[params[i]];
            if (f)
            {
                params[i] = instance(params[i]);
            }
        }

        return create(reg[factoryName].className, params)
    }
    this.instance = instance;

    function create(type, params)
    {
        var constructor = new Function('return ' + type)();
        var inst = new constructor();
        inst.init && inst.init.apply(inst, params);
        return inst;
    }
}

var c = new Container(registration);
var f = c.instance('Baz');
Look for part 2 coming soon. Happy scripting!

Got something to say?

Please note: Constructive criticism is welcome. Rude or vulgar comments however, are not and will be removed during moderation.