binding a concrete implementation to a concrete implementation

1,579 views
Skip to first unread message

Yuen Ho Wong

unread,
Dec 16, 2007, 11:17:53 PM12/16/07
to google-guice
Hi Guicers,

Before anyone passes any judgments, I would just like to know if it's
possible to do something like bind(A.class).to(A.class), where A is a
concrete class, or bind(A.class).to(B.class) where A could be an
abstract class, or a proxy/wrapper/facet to B.class (i.e no direct
interface/implementation relationship).

According to my little tests, the first case doesn't seem to be
possible and I'd like to petition to enable just that. The rationale
is simple - the client code should not know when the injected class is
an interface or a concrete class because it makes no difference to the
user anyway. It's good practice to separate an implementation from its
interface, but there's no reason to enforce this practice in the
binding DSL for the reason aforementioned and it only doubles the size
(and maintenance costs) of your code where suddenly you not just have
an implementation class, but also an interface for every
implementation class you plan to inject. If the API changes all the
time, this issue quickly becomes a maintenance nightmare. Also, with
the new versions of the Mock frameworks, one can easily mock a
concrete class anyway, so in effect, duck typing is proved to easily
achievable with Java 1.5.

Thoughts?

Yuen

Josh McDonald

unread,
Dec 16, 2007, 11:37:24 PM12/16/07
to google...@googlegroups.com
The thing is, it shouldn't be the client code that's doing the bind(Foo).to(Bar). It's just the module definition code, which pretty much needs to know what everything is - interface, abstract class, or concrete impl...

-Josh
--
"This is crazy! Why are we talking about going to bed with Wilma Flintstone... She'll never leave Fred and we know it. "

:: Josh 'G-Funk' McDonald
:: 0437 221 380 :: jo...@gfunk007.com

Yuen Ho Wong

unread,
Dec 16, 2007, 11:46:50 PM12/16/07
to google-guice
You are right, the client isn't suppose to do any binding, but in no
way does that obligate the module to know what everything is. All it
needs to remember is a list of 3 tuples (key, annotation, value). Key
and value may or may not be the exact same thing. Guice shouldn't
need to know about anything more then what was given to store this
binding. That's what I think about what dependency injection is. It
should solve the tight coupling problems for me, not solve the tight
coupling problem by introducing more maintenance problem.


On Dec 16, 11:37 pm, "Josh McDonald" <dzn...@gmail.com> wrote:
> The thing is, it shouldn't be the client code that's doing the
> bind(Foo).to(Bar). It's just the module definition code, which pretty much
> needs to know what everything is - interface, abstract class, or concrete
> impl...
>
> -Josh
>
> :: 0437 221 380 :: j...@gfunk007.com

Dhanji R. Prasanna

unread,
Dec 16, 2007, 11:47:17 PM12/16/07
to google...@googlegroups.com
On 12/17/07, Yuen Ho Wong <wyu...@gmail.com> wrote:
>
> Hi Guicers,
>
> Before anyone passes any judgments, I would just like to know if it's
> possible to do something like bind(A.class).to(A.class), where A is a
> concrete class, or bind(A.class).to(B.class) where A could be an
> abstract class, or a proxy/wrapper/facet to B.class (i.e no direct
> interface/implementation relationship).

You can bind A to B if B is a subtype of A. If you want to bind A to A
explicitly, simply write:

bind(A.class).in(...);

>
> According to my little tests, the first case doesn't seem to be
> possible and I'd like to petition to enable just that. The rationale
> is simple - the client code should not know when the injected class is
> an interface or a concrete class because it makes no difference to the
> user anyway. It's good practice to separate an implementation from its
> interface, but there's no reason to enforce this practice in the
> binding DSL

I dont follow--
Are you suggesting we get rid of the static typing in bindings?
How does it matter if client code knows/cares about whether a member
variable is concrete or abstract? Isn't that the point of Dependency
Injection?

Also, with
> the new versions of the Mock frameworks, one can easily mock a
> concrete class anyway, so in effect, duck typing is proved to easily
> achievable with Java 1.5.

Duck typing is not available in Java except via contortions like
reflection. Mocking is not duck typing, duck typing typically means
two things:

- evaluating types in expressions at runtime (dynamic typing)
- resolving dispatch at runtime by lexical similarity

Java does neither of these (though I hear a bytecode instruction to
facilitate the latter may be coming in 7's JVM).

Dhanji.

Josh McDonald

unread,
Dec 16, 2007, 11:53:55 PM12/16/07
to google...@googlegroups.com
Dependency injection can't absolve you of the need to know where and how your application fits together though. It allows you to put it all in one place, rather than requiring individual components to know where to look for their dependencies. In Spring it's a giant xml file (of eternal suffering), in Guice it's in your java setup code.

-Josh
--
"This is crazy! Why are we talking about going to bed with Wilma Flintstone... She'll never leave Fred and we know it. "

:: Josh 'G-Funk' McDonald
:: 0437 221 380 :: jo...@gfunk007.com
Message has been deleted
Message has been deleted

Yuen Ho Wong

unread,
Dec 17, 2007, 1:01:28 AM12/17/07
to google-guice
> You can bind A to B if B is a subtype of A. If you want to bind A to A
> explicitly, simply write:

> bind(A.class).in(...);

Ah that's the hack I'm looking for.

> I dont follow--
> Are you suggesting we get rid of the static typing in bindings?

Yes and no. This needs to be discussed a little more I guess. There
are 2 issues here.

1) The DSL usability problem. In English, the word "bind" is usually
bound to a proposition "to" (pun intended), so if you say
bind(A.class).in(...), it's a little weird and not particularly
intuitive.

2) I can imagine in the course of re-factoring old code to take
advantage of Guice, there would be some existing decorator/proxy/
facets that are wrapping some ugly old code. It would be nice if
bind(A.class).to(B.class) works, where A and B have no immediate
parent child relationship whatsoever. I know provider already enables
this, but that's 1 more layer of code. The anonymous class syntax is
ugly and a top level provider class is just even more code in more
disparate places that doesn't really enable a reuse. Is there a clean
way to bind to just a method to some class that returns A or a subtype
of A?

> How does it matter if client code knows/cares about whether a member
> variable is concrete or abstract? Isn't that the point of Dependency
> Injection?

It doesn't, that's what I'm saying.

> Duck typing is not available in Java except via contortions like
> reflection. Mocking is not duck typing, duck typing typically means
> two things:

> - evaluating types in expressions at runtime (dynamic typing)
> - resolving dispatch at runtime by lexical similarity

> Java does neither of these (though I hear a bytecode instruction to
> facilitate the latter may be coming in 7's JVM).

No contention here. My use of the term duck typing is abusive. I
actually mean programming to an interface without explicitly having to
extract a static interface.

Stuart McCulloch

unread,
Dec 17, 2007, 2:31:45 AM12/17/07
to google...@googlegroups.com
On 17/12/2007, Yuen Ho Wong <wyu...@gmail.com> wrote:

> You can bind A to B if B is a subtype of A. If you want to bind A to A
> explicitly, simply write:
>
> bind(A.class).in(...);
>

Ah that's the hack I'm looking for.

except it's not really a 'hack' - it's more like DRY (don't repeat yourself) because
there's no point in mentioning A.class twice if you're just going to bind it to itself.

also, if you @Inject A (where A is a concrete class) and don't supply any explicit
bindings, Guice will inject an instance of A - so allowing bind(A.class).to(A.class)
doesn't add much value, as that's actually the default if no bindings for A are given.

> I dont follow--
> Are you suggesting we get rid of the static typing in bindings?

Yes and no. This needs to be discussed a little more I guess. There
are 2 issues here.

1) The DSL usability problem. In English, the word "bind" is usually
bound to a proposition "to" (pun intended), so if you say
bind(A.class).in(...), it's a little weird and not particularly
intuitive.

bind(A.class).in(...) is just shorthand for bind(A.class).to(A.class).in(...)
imho this is just as understandable (like in English can't => can not)

2) I can imagine in the course of re-factoring old code to take
advantage of Guice, there would be some existing decorator/proxy/
facets that are wrapping some ugly old code. It would be nice if
bind(A.class).to(B.class) works, where A and B have no immediate
parent child relationship whatsoever. I know provider already enables
this, but that's 1 more layer of code. The anonymous class syntax is
ugly and a top level provider class is just even more code in more
disparate places that doesn't really enable a reuse.

but for the old code to accept an instance of B in place of A where there's
no relationship between A and B then there needs to be some proxying -
and in a lot of cases this is non-trivial and can't be automated (so using a
Provider to explicity proxy it would be preferable and much safer)

even in those cases where it could be automated it would be better to do
this outside of the core in a support library, which would be possible with
issue 49 ( http://code.google.com/p/google-guice/issues/detail?id=49)

> How does it matter if client code knows/cares about whether a member
> variable is concrete or abstract? Isn't that the point of Dependency
> Injection?

It doesn't, that's what I'm saying.

> Duck typing is not available in Java except via contortions like
> reflection. Mocking is not duck typing, duck typing typically means
> two things:
>
> - evaluating types in expressions at runtime (dynamic typing)
> - resolving dispatch at runtime by lexical similarity
>
> Java does neither of these (though I hear a bytecode instruction to
> facilitate the latter may be coming in 7's JVM).

No contention here. My use of the term duck typing is abusive. I
actually mean programming to an interface without explicitly having to
extract a static interface.





--
Cheers, Stuart

Yuen Ho Wong

unread,
Dec 17, 2007, 10:52:54 AM12/17/07
to google-guice
> except it's not really a 'hack' - it's more like DRY (don't repeat yourself)
> because
> there's no point in mentioning A.class twice if you're just going to bind it
> to itself.
> also, if you @Inject A (where A is a concrete class) and don't supply any
> explicit
> bindings, Guice will inject an instance of A - so allowing bind(A.class).to(
> A.class)
> doesn't add much value, as that's actually the default if no bindings for A
> are given.

I would actually argue that it makes the code more explicit and clear
by saying binding A to A. Just bind A without specifying it's
destination and hoping that it would automagically bind to itself is
like asking calling your girlfriend up and hope that she will pick up
your laundry by not saying a single word. Ok there's an issue of scope
here but still, just a thought.

> bind(A.class).in(...) is just shorthand for bind(A.class).to(A.class
> ).in(...)
> imho this is just as understandable (like in English can't => can not)

I'd agree with you on the short hand part if
bind(A.class).to(A.class).to(...) works as well as
bind(A.class).in(..). But bind(A.class).to(A.class) gives me an error
saying "Binding points to itself", which is apparently allowed by
magic. All this conversation really boils down to the fact that I
think bind(A.class).to(A.class) should just work.

> but for the old code to accept an instance of B in place of A where there's
> no relationship between A and B then there needs to be some proxying -
> and in a lot of cases this is non-trivial and can't be automated (so using a
> Provider to explicity proxy it would be preferable and much safer)
>
> even in those cases where it could be automated it would be better to do
> this outside of the core in a support library, which would be possible with
> issue 49 (http://code.google.com/p/google-guice/issues/detail?id=49)

It might be advantageous if there were methods such as
bind(A.class).toInstanceMethod(B.class).giveMeAnA([params]), and
bind(A.class).toStaticMethod(B.class).giveMeAnA([params]), where
giveMeAnA() is an actual method that belongs to A. The two methods I
mentioned would have the signature of <T> T toInstanceMethod(Class<T>
cls), and <T> T toStaticMethod(Class<T> cls), and the cls param does
not have to have any parent child relationship with A. The reason this
is useful is because there are many cases where changing B's
implementation is not desirable or even possible. toInstanceMethod
will have the additional constraint that B must have a default
constructor or an injectable constructor. annotatedWith() will not be
support in these 2 new methods because that assumed the user has or
will change the implementation of B by adding Guice annotations, which
defeats the purpose of the 2 methods. But then of course, I do realize
the returned object of type T in these 2 methods will have to be
mangled with some convoluted proxy or some code generator.

Stuart McCulloch

unread,
Dec 17, 2007, 10:26:32 PM12/17/07
to google...@googlegroups.com
On 17/12/2007, Yuen Ho Wong <wyu...@gmail.com> wrote:

> except it's not really a 'hack' - it's more like DRY (don't repeat yourself)
> because
> there's no point in mentioning A.class twice if you're just going to bind it
> to itself.
> also, if you @Inject A (where A is a concrete class) and don't supply any
> explicit
> bindings, Guice will inject an instance of A - so allowing bind(A.class).to(
> A.class)
> doesn't add much value, as that's actually the default if no bindings for A
> are given.

I would actually argue that it makes the code more explicit and clear
by saying binding A to A. Just bind A without specifying it's
destination and hoping that it would  automagically bind to itself is
like asking calling your girlfriend up and hope that she will pick up
your laundry by not saying a single word.

unless that was the default arrangement understood by both parties ;)
another real-world example: when I go to my usual cafe they typically
ask: 'the usual?' and I just say 'yes'... but this is veering off topic!


Ok there's an issue of scope
here but still, just a thought.

> bind(A.class).in(...) is just shorthand for bind(A.class).to(A.class
> ).in(...)
> imho this is just as understandable (like in English can't => can not)

I'd agree with you on the short hand part if
bind(A.class).to(A.class).to(...) works as well as
bind(A.class).in(..). But bind(A.class).to(A.class) gives me an error
saying "Binding points to itself", which is apparently allowed by
magic. All this conversation really boils down to the fact that I
think bind(A.class).to(A.class) should just work.

I can see disallowing bind(A.class).to(A.class) when A is an interface, as it's
likely the developer has made a typo - perhaps Bob/Kevin can explain the
reasoning behind the general case... it might be similar

> but for the old code to accept an instance of B in place of A where there's
> no relationship between A and B then there needs to be some proxying -
> and in a lot of cases this is non-trivial and can't be automated (so using a
> Provider to explicity proxy it would be preferable and much safer)
>
> even in those cases where it could be automated it would be better to do
> this outside of the core in a support library, which would be possible with
> issue 49 (http://code.google.com/p/google-guice/issues/detail?id=49)

It might be advantageous if there were methods such as
bind(A.class ).toInstanceMethod(B.class).giveMeAnA([params]), and

bind(A.class).toStaticMethod(B.class).giveMeAnA([params]), where
giveMeAnA() is an actual method that belongs to A.

( btw, I think you meant giveMeAnA() is a method from B that returns A? )

IMHO that would be hard to understand for a newbie - at first glance it looks
like you're binding a class to a method, but I assume giveMeAnA(...) is really
acting as a provider - but why not use a provider, it would be much clearer?

alternatively, if you don't want the overhead of an extra class there's always
the @ProviderMethod feature that I believe is scheduled for the next release:

   http://code.google.com/p/google-guice/issues/detail?id=83


The two methods I
mentioned would have the signature of <T> T toInstanceMethod(Class<T>
cls), and <T> T toStaticMethod(Class<T> cls), and the cls param does
not have to have any parent child relationship with A. The reason this
is useful is because there are many cases where changing B's
implementation is not desirable or even possible.

I still think using a Provider class is more maintainable as you can keep A
and B separate (ie. A doesn't need to have a compile dependency on B)

toInstanceMethod
will have the additional constraint that B must have a default
constructor or an injectable constructor

but typically if changing B's implementation is not desirable/possible then
this won't be true, and you'll need to use a provider class/method to build
the right object anyway

. annotatedWith() will not be
support in these 2 new methods because that assumed the user has or
will change the implementation of B by adding Guice annotations, which
defeats the purpose of the 2 methods. But then of course, I do realize
the returned object of type T in these 2 methods will have to be
mangled with some convoluted proxy or some code generator.

I still think this belongs outside of the core (and could be implemented
as a legacy support library) - that way core remains lean and mean :)

--
Cheers, Stuart

Yuen Ho Wong

unread,
Dec 18, 2007, 11:33:26 AM12/18/07
to google-guice
Yeah the fact that bind(A.class).to(A.class) doesn't work really
throws me off. Should file a bug for this?


Yes B is sort of a provider that provides A, the problem is that there
are cases where users have no control of the implementation of B but
still want to take advantage of the juiciness of Guice.

I don't have a particular reason against implementing the 2 methods in
a legacy support library. That library may very well just consist of a
LegacySupportBindingBuilder that supports the 2 methods and hide
AnnotatedBindingBuilder, and a AbstractLegacySupportModule that gives
you that LegacySupportBindingBuilder. File for an enhancement?

Logan Johnson

unread,
Dec 18, 2007, 11:46:46 AM12/18/07
to google...@googlegroups.com
All for convenience and utility libraries, but it's worth pointing out that if you have some B with a method that provides A, and B is not a Provider, it's not a big deal to wrap a Provider around that method call.  It's what Guice would have to do internally anyway.

Stuart McCulloch

unread,
Dec 18, 2007, 12:06:55 PM12/18/07
to google...@googlegroups.com
On 19/12/2007, Yuen Ho Wong <wyu...@gmail.com> wrote:

Yeah the fact that bind(A.class).to(A.class) doesn't work really
throws me off. Should file a bug for this?

Yes B is sort of a provider that provides A, the problem is that there
are cases where users have no control of the implementation of B but
still want to take advantage of the juiciness of Guice.

you can still use B in a Provider class even if you don't have
control of its implementation - just use the builder approach
(ie. you write a Provider class with the glue to turn B into A)

I don't have a particular reason against implementing the 2 methods in
a legacy support library. That library may very well just consist of a
LegacySupportBindingBuilder that supports the 2 methods and hide
AnnotatedBindingBuilder, and a AbstractLegacySupportModule that gives
you that LegacySupportBindingBuilder. File for an enhancement?

imho this doesn't really require an issue, as I think it can
be done outside of the core (ie. outside of the Guice jar)
like the many other (existing) extensions to Guice...

but feel free to log a request if you feel strongly about it

Reply all
Reply to author
Forward
0 new messages