Paul Hammant's Blog: Crazy Bob and type safety for Dependency Injection
Not so crazy anymore
I bumped into Bob Lee at Greg Stein's birthday party in San Francisco last night. Tis always a pleasure. Despite the drink/music/company we got into a debate about Guice and its love of type-safety. Congrats on the Jolt award win by the way Bob & Kevin.My proposal was that, in addition to the binding-annotations magic of Guice they could soften a little and learn to live with parameter names as another way to disambiguate. Developers using Guice (or PicoContainer/others) should be able to choose utter runtime-type-safety or step back a little and just live with the fact that no matter how hard you try there can always be a binding mismatch somewhere and good testing is the way to mitigate that risk.
Anyway, Parameter name access did not make it into Java 6, and it looks like they're not doing so for Java 7 either. Of course, I'm happy with Paranamer for now.
Ruby teaching lessons to Java ?
There are many lessons perhaps, but I think that less-is-more (terse yet expressive) and convention-over-configuration are two of the important ones. If you ask the Java escapees who love Ruby why they do, they quite often state they feel more productive because there is less boiler plate code ... including annotations. Well that and some other reasons, which are not so important to this blog entry.Inject is the new Import
Brian Slesinsky's article is great of course, but brian has it wrong in that fields are not the way forward. It is and should be constructors that are the best way to declare component dependencies. I can't help but feel that there is too much typing for Java's constructors though:public class Foo { private Bar bar; private Baz baz; public Foo(Bar bar, Baz, baz) { this.bar = bar; this.baz = baz; } public Foo(Bar bar) { this.bar = bar; baz = new DefaultBaz(); } public Foo(Bar bar) { this(bar, new DefaultBaz()); } }It would be nicer to have a better syntax for member variables via constructors:
public class Foo { private Bar bar@; private Baz baz@; public Foo(Bar bar, Baz, baz) {} public Foo(Bar bar) { baz = new DefaultBaz(); } }Where the @ at the tail of the member var names means pull it from the constructor. Or perhaps final can be imply the same for a constructor ...
public class Foo { private final Bar bar; private final Baz baz; public Foo(Bar bar, Baz, baz) { } public Foo(Bar bar) { baz = new DefaultBaz(); } }
DI in the language?
It is what Bob really wants I think - Dependency Injection in the JDK/language.Maybe Java could go further still and allow some variable constructor injection (no container needed)
public class Foo { private final Bar bar@; private final Baz baz@; public Foo(@) { if (baz == null) { baz = new DefaultBaz(); } } } new Foo(new BarImpl()) // compiles and runs new Foo(new BarImpl(), new FastBaz()) // compiles and runs new Foo(new FastBaz(), new BarImpl()) // hmmm, maybe or maybe not new Foo() // does not compile (needs at least a Bar)Maybe rather than have a library in the JDK the language handles it a little.
Baz myBaz = new MyBaz(); Foo foo = new Foo(@, myBaz);The @ means when instantiating Foo, if the required parameters are not supplied, look to the DI container to satisfy parameters. The DI container is the one scoped presently. That means the one that instantiated the current class. How about this variation for making a new scoped container for
Container container = new ChildContainer(@); container.addComponent(Baz.class, new MyBaz()); Foo foo = container.instantiate(Foo.class);There's a difference between something on thread local, and something that was scoped at time of a class' creation. This stuff is definitely the latter, and that is not something that Java currently supports, let alone as a pseudo-language feature.
Meh. There are lots of issues with all this though. What to do with super-class constructors? What about binding annotations and parameter names for disambiguation? Will this varargs type solution for differing types work? Will IDE makers go nuts?
Constructors considered harmful.
Gilad Bracha blogged the above, pointing out that other languages had designs that allow participation in instantiation. Amongst other things he lamented that constructors could not return something other than the class the instantiator was asking for. In effect new Foo() would always return a Foo. Never would it return Foo-subclass or a singleton ref to a shared Foo. Lots of interesting stuff.The ideas I'm discussing in this blog entry do not go as far as the casual interception of class instantiation, just a more seamless way that DI can pay a part in it.