Dagger: Respect other Optional<T> types

Created on 1 Jun 2017  路  9Comments  路  Source: google/dagger

It'd be great if Optional<T> types other than Guava and Java 8 would be accepted by Dagger 2. It's costly to include all of Guava in an Android app, and using Java 8 APIs aren't an option for many apps, due to only being available on API 24+.

Happy for another alternative though - we just need working optional/nullable binding functionality.

feature request

Most helpful comment

Dagger could do that, but I don't think we want a world with Guava's Optional, Java8's version, and custom versions

But there are cases when it makes sense:
Guava is a big library and it's doesn't sound reasonable to include it just because of Optional even if you use ProGuard
Java 8 Optional is not available on Android before API level 24 (pre-24 devices is about 70%)

I still like an idea about Optional factory, but maybe an alternative solution Dagger could provide own very simple Optional implementation for such cases as separate artifact or as part of runtime library (something like DaggerOptional or OptionalDependency)

All 9 comments

One problem is how to construct those alternative Optional values?

Maybe optional bindings should be allowed at nullable injection points? (Should the injected object really worry whether a dependency comes from an optional binding or a nullable binding?)

Very much agreed about allowing optional injections at nullable injection points. That'd solve the problem nicely.

We're working to make Guava more friendly to Android, but we still do assume you're using ProGuard or something to remove unused code.

We do not plan to allow @Nullable to mean optional (i.e., works even if there is no binding), because @Nullable already means it allows null values from the required binding.

I don't know how we could allow arbitrary "Optional" types, since we'd need to know how to construct present and absent instances of them. It's not like @Nullable where any annotation with the same simple name works.

One way would be:

public class AnyClass {
  @dagger.OptionalFactory
  public static <T> com.example.Optional<T> anyName(@Nullable T value) {
    return com.example.Optional.fromNully(value);
  }
}

Would it be possible to allow injections to be annotated with a new @dagger.Optional annotation to signal that a null value can potentially mean the dependency was left unsatisfied?

// bar can be null
@Provides Foo foo(@dagger.Optional Bar bar)

// barProvider won't be null, but the result of get() can be
@Provides Foo foo(@dagger.Optional Provider<Bar> barProvider)

The problem with including Guava is also the code size/method count cost during development. We do indeed use Proguard, but not for debug builds.

Would it be possible to allow injections to be annotated with a new @dagger.Optional annotation to signal that a null value can potentially mean the dependency was left unsatisfied?

@Nullable already does that.

Re: something like @dagger.OptionalFactory, Dagger _could_ do that, but I don't think we want a world with Guava's Optional, Java8's version, and custom versions. Even if that wasn't a concern, this sounds like something that could easily be abused for confusing bindings.

@nullable already does that.

I can't seem to implement this behavior. The following configuration won't compile unless a Bar binding is available:

@Module public abstract class OptionalModule {
     @BindsOptionalOf public abstract Bar bar();
}
@Module public class MyModule {
    @Provides Foo foo(@android.support.annotation.Nullable Bar bar) { ... }
}

I'm using version 2.11-rc2.

So unless I'm missing something, @Nullable does not allow optional bindings.

What're your thoughts on allowing this?

Btw, my use case is where I want to supply a @Module via a library that utilizes a binding, if provided by the caller, but otherwise falls back to a default implementation, which I think is quite reasonable when clearly documented.

@netdpb already mentioned that that is Working As Intended. @Nullable means the binding may have a null value, not that the binding may or may not exist. Changing this would have large impacts on binding graphs for all dagger users

Dagger could do that, but I don't think we want a world with Guava's Optional, Java8's version, and custom versions

But there are cases when it makes sense:
Guava is a big library and it's doesn't sound reasonable to include it just because of Optional even if you use ProGuard
Java 8 Optional is not available on Android before API level 24 (pre-24 devices is about 70%)

I still like an idea about Optional factory, but maybe an alternative solution Dagger could provide own very simple Optional implementation for such cases as separate artifact or as part of runtime library (something like DaggerOptional or OptionalDependency)

Was this page helpful?
0 / 5 - 0 ratings