@Provides, Providers (and singleton objects vs factories)...

801 views
Skip to first unread message

Kevin Burton

unread,
Oct 16, 2014, 7:19:07 PM10/16/14
to google...@googlegroups.com
I humbly propose that these concepts are rather confusing in Guice

@Provides vs Providers

They both use similar mechanisms... IE providing the value of an object, but they do it differently and the semantics are confusing.

Also, Providers can provide either one object, or many... 


Seems this is mostly done for lazy loading, or expensive loading , or creating a new object per get() call.

So when I see Provider<Foo> ... I don't know if that call is potentially expensive the first time.

I also don't know if I'm going to get one object (a singleton) or lots of them.  

Or if it's a rather simple object to instantiate it's just that we're doing so lazily.

Of course maybe I'm insane ;) ... which is entirely possible.

Tim Peierls

unread,
Oct 17, 2014, 12:32:15 PM10/17/14
to google...@googlegroups.com
On Thu, Oct 16, 2014 at 7:19 PM, Kevin Burton <burto...@gmail.com> wrote:
I humbly propose that these concepts are rather confusing in Guice

@Provides vs Providers

They both use similar mechanisms... IE providing the value of an object, but they do it differently and the semantics are confusing.

Here's one way to think about it:

@Provides appears only when configuring bindings with a Module. Annotating a Module method with @Provides -- and possibly some scoping annotation -- sets up a binding that means "this method is how to provide an instance of the return type (in the specified scope, if any)". You won't see it in regular code. It's a very convenient shorthand for something that can be accomplished more clumsily with explicit calls to bind() and custom providers.

Provider<T> mainly shows up at injection points in regular code. (Another place you'll see it is as the supertype of a custom provider, but many of those cases can be expressed more simply with @Provides.) At an injection point, it means "instead of injecting a T directly, I'm giving you a way to get() an instance of T". It doesn't promise any more than that. In particular, it doesn't mean that you'll get a new instance of T every time you call get() -- though you might.

 
So when I see Provider<Foo> ... I don't know if that call is potentially expensive the first time.
I also don't know if I'm going to get one object (a singleton) or lots of them. 
Or if it's a rather simple object to instantiate it's just that we're doing so lazily.

All correct, but you typically won't be presented with a Provider<Foo> in the wild; you'll be writing code that needs to be injected with a Foo, and you'll know of some reason that you want to defer provision of the Foo to some point under your control after the injection point -- and it could be for any of the three things you mention, or for something like circularity -- that's when you'll use Provider<Foo> instead. 

If you do find yourself facing a Provider<Foo> at an injection point, you should assume that the person who put it there wants to defer the provision of a Foo until one is actually needed, at which point you call get(). It's also safe to assume that you should call get() every time you need a Foo in the context of the injection point. If it's bound as a singleton, no harm done; if it's bound in some other kind of scope (or unscoped) you'll be making sure that you're getting a correctly-scoped instance.

--tim

Christian Gruber

unread,
Oct 22, 2014, 10:38:22 PM10/22/14
to google...@googlegroups.com
At one point in the early days of Dagger we toyed with the idea of using the term @Contributes instead of @Provides as part of cleaming the terminology up.  Using @Bind or @Binds would also be good.  We stayed with @Provides because it was a known quantity and not _that_ confusing.  Guice, of course, has the larger problem of a huge install base so altering the configuration language primitives becomes a burden - either to maintain backward compatibility or to forward-migrate folks.

But for what it's worth, when I see @Provides I think "@ConfiguresABindingFor" with reference to the return type or the qualified return type. That conceptual mapping might make it easier.

-christian.

--
You received this message because you are subscribed to the Google Groups "google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email to google-guice...@googlegroups.com.
To post to this group, send email to google...@googlegroups.com.
Visit this group at http://groups.google.com/group/google-guice.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-guice/CA%2BF8eeS%3DH5GoLqciM1Hjg4M1NLgY1QoaehUToWzy0fZLSAcfiA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages