square / dagger

A fast dependency injector for Android and Java.
https://square.github.io/dagger/
Apache License 2.0
7.31k stars 3.07k forks source link

Default bindings for parameterized types? #106

Open swankjesse opened 11 years ago

swankjesse commented 11 years ago

Dagger currently fails to create @Inject bindings for classes with type parameters. We could fix this. We should weight the upsides and the downsides; one big downside is that it'll require a ton of code, possibly even something that parses a type like Converter<Payment>.

See also Guice Punches Erasure In The Face.

cgruber commented 11 years ago

Dagger currently fails to create @Inject bindings for classes with type parameters.

Wait… we do support binding something to Foo<Bar> and injecting Foo<Bar> now, no? Just not Foo<T>. Yes?

We could fix this. We should weight the upsides and the downsides; one big downside is that it'll require a ton of code, possibly even something that parses a type like Converter<Payment>.

See also Guice Punches Erasure In The Face.

If we do it, we need to do it, if possible, with minimal currying around of extra type information. That is, we need to validate at compile-time that

@Inject Foo<Bar> foobar;

is satisfied by

@Provides Foo<T> provideFoo() { … }

But I don't think we can get around the fundamental issue represented by the guarded list. One CAN just cast the thing to the generalized form, and bypass type safety of the lists. In other words, we can make a gun with a safety, teach good gun safety, but we can't prevent someone from flipping off that safety as they line the sight up at their boot.

I guess the question is… do we do the work to get TypeLiteral or some such into a built-in injection and what would the impact of this be on performance?

And, what real problems, not merely robot legs (and we have a larger issue there, as @swankjesse and I discussed), but real use-cases our users are encountering in production systems will this address, and can the problem be solved in a different way that is reasonable? What piece of software can't they write that they really should write?

pforhan commented 11 years ago

In the case where I encountered this, it was easy enough to work around. All I ask for is that if it compiles, it will run. This was compiling but failing at runtime.

swankjesse commented 11 years ago

I don't think I was clear enough. This only impacts @Inject bindings. For example, you can't do this:

  public class Foo<T> {
    @Inject Foo() {
    }
  }

  public class Bar {
    @Inject Foo<String> fooOfString;
  }
cgruber commented 11 years ago

On 12 Nov 2012, at 13:12, Jesse Wilson wrote:

I don't think I was clear enough. This only impacts @Inject bindings. For example, you can't do this:

public class Foo<T> {
@Inject Foo() {
}
}

public class Bar {
@Inject Foo<String> fooOfString;
}

Ok - check. This makes sense, but it seems like it would be only relevant to JIT bindings, given that one could bind Foo in an @Provides. This is sort of close to using Dagger as a factory implicitly, and I wonder if it's a power or a code-smell. I'd need to see more samples, I think.

I think it wouldn't be horrid to make work… just would want to make sure we don't end up with it being too easy to do the wrong thing or have surprising behavior. As was mentioned - if it compiles, it should work. Can we guarantee that?