Someone on the Herding Code podcast No. 68, http://herdingcode.com/?p=231, stated that IOC containers had no place with Python or Javascript, or words to that effect. I'm assuming this is conventional wisdom and that it applies to all dynamic languages. Why? What is it about dynamic languages that makes IOC containers unnecessary?
One of the main features of IOC containers is that you can automatically "wire" your modules together at runtime. In dynamic languages you can do this fairly easily without any fancy reflection-based logic. However, IOC containers are a useful pattern that many people understand and it may sometimes be of some benefit to use the same design style. See this article for another viewpoint.
Because they are already built into the language.
An IoC container provides two things:
- dynamic binding
- a dynamic language (usually an incredibly crappy one, built on top of XML or in newer versions on top of Java annotations/.NET attributes)
Dynamic binding is already part of the dynamic language and the dynamic language is already a dynamic language. Therefore, an IoC container simply doesn't make sense: the language is already an IoC container.
Another way to look at it: what is it that an IoC container allows you to do? It allows you to take independent components and wire them up together into an application, without any of the components knowing anything about each other. There is a name for wiring independent pieces together into an application: scripting! (That's pretty much the definition of scripting.) Many dynamic languages happen to also be pretty good at scripting, therefore they are perfect as IoC containers.
Please note that I am not talking about Dependency Injection or Inversion of Control. DI and IoC are just as important in dynamic languages as they are in static languages, for exactly the same reasons. What I am talking about are IoC containers and DI frameworks. Those tools are unnecessary, the design principles aren't.
IoC provides a mechanism to break the coupling you get when an object calls 'new' on another class. This coupling ties the calling object the the instantiated implementation of whatever interface it implements.
In static languages when you reference a class by name (to call new on it), there is no ambiguity. This is a tight coupling to a specific class.
In dynamic languages calling 'new X' is a placeholder for "instantiate whatever class is defined as X at the point of execution". This is a looser coupling, as it's only coupled to the name X.
This subtle difference means that in a dynamic language you can usually change what X is, so the decision as to which class is instantiated is still modifiable outside of the calling class.
However, personally I find there are two advantages to IoC that I don't get by relying on the dynamic language to allow injection.
One of the side effects of passing dependencies in through constructors is that you end up with "building block" classes that are very decoupled, reusable and easy to test. They have no idea what context they are intended to be used in, so you can reuse them all over the place.
The other result is having explicit code to do the wiring. Done correctly this cleanly represents the structure of your application and it's decomposition into subsystems and life-cycles. This makes people explicitly decide which life-cycle or subsystem they want to associate their class with (when writing the wiring code), and concentrate on the behavior of the object when writing the class.
Like Jörg W Mittag said.. "Those tools are unnecessary, the design principles aren't." I believe they are unnecessary, but done right, still valuable.
IoC containers really allow for a compositional layer in statically typed, procedural/OO languages.
This compositional layer exists relatively naturally in dynamic languages such as Python or Javascript (consider that Javascript is heavily based on Scheme).
You could probably make a good argument that IoC containers are just a generalization of the Interpreter pattern.
I have a different opinion. I think IOC containers certainly have a role in dynamic languages.
I do not share the opinion that a language being dynamic removes the need for a clearly structured composition of objects. Or that a dynamic language 'provides' the same functionality.
An IOC container is simply a tool to manage this organization.
Even in a dynamic language I want to 'wire' together components. Without making hard dependencies between those components. Or maybe even without specifying the actual implementation class for those components.
Herding Code 82 (6/6/10) compares Ruby with .NET and includes some detailed discussion on the extent to which .NET needs more IOC/DI than Ruby.