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.
Gilead 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.
Mar 16, 2008
Updates