TLDR: This is a feature request for allowing @BindsOptionalOf bindings to be conditionally provided at runtime, akin to how @ElementsIntoSet works for mulltibindings
Background: Conditionally providing multibindings
Say we have 1) a multibinding of Foos; and 2) an injectable implentation of Foo (i.e. FooImpl) :
@Multibinds fun foos(): Set<Foo>
@Provides fun fooImpl(): FooImpl { ... } // where FooImpl : Foo
Say we'd like to conditionally include FooImpl on Set<Foo> at compile time (e.g. include on beta builds, but not release ones). In this case we can:
// Include this on *beta* builds only
@Binds
@IntoSet
fun intoFoos(impl: FooImpl): Foo
It is also possible to conditionally include FooImpl on Set<Foo> at runtime (e.g. depending on a runtime feature flag):
@Provides
@ElementsIntoSet
fun intoFoos(impl: FooImpl): Set<Foo> = if (featureEnabled) setOf(impl) else emptySet()
Problem: Conditionally providing optional bindings
Let's change the example above slightly so that we have an optional Foo rather than a set of Foos:
@BindsOptionalOf fun optionalFoo(): Foo // ← change this
@Provides fun fooImpl(): FooImpl { ... } // where FooImpl : Foo
We can still conditionally provide an Optional<Foo> at compile-time as follows:
// Include this on *beta* builds only
@Binds fun foo(impl: FooImpl): Foo
The problem: there's no easy way to conditionally provide an Optional<Foo> at runtime. This is because there's no equivalent to @ElementsIntoSet for optional bindings.
Workaround
Fortunatelly there's a way to overcome the problem above. We need to replace @BindsOptionalOf fun optionalFoo(): Foo with:
@Provides
fun optionalFoo(@Bar foo: Optional<Optional<Foo>>): Optional<Foo> // ← change this
= if (foo.isPresent() && foo.get().isPresent()) foo.get().get() else Optional.empty
@Qualifier annotation class Bar // ← needed for disambiguating `Optional<Foo>` bindings
@BindsOptionalOf
@Bar
fun optionalOptionalFoo(): Optional<Foo> // ← add this
Then, we can conditionally provide an Optional<Foo> at runtime as follows:
@Provides
@Bar
fun foo(impl: FooImpl): Optional<Foo> = if (featureEnabled) Optional.of(impl) else Optional.empty()
Potential solution (feature request)
The workaround above works, but it's far from ideal (e.g. having to use a qualifier, nested optionals, intermediate binding). Ideally I'd like to be able to write something like this:
@BindsOptionalOf fun optionalFoo(): Foo
@ProvidesOptionalOf // ← this doesn't exist
fun foo(impl: FooImpl): Optional<Foo> = if (featureEnabled) Optional.of(impl) else Optional.empty()
Would it be possible to implement this feature?
TLDR: This is a feature request for allowing
@BindsOptionalOfbindings to be conditionally provided at runtime, akin to how@ElementsIntoSetworks for mulltibindingsBackground: Conditionally providing multibindings
Say we have 1) a multibinding of
Foos; and 2) an injectable implentation ofFoo(i.e.FooImpl) :Say we'd like to conditionally include
FooImplonSet<Foo>at compile time (e.g. include on beta builds, but not release ones). In this case we can:It is also possible to conditionally include
FooImplonSet<Foo>at runtime (e.g. depending on a runtime feature flag):Problem: Conditionally providing optional bindings
Let's change the example above slightly so that we have an optional
Foorather than a set ofFoos:We can still conditionally provide an
Optional<Foo>at compile-time as follows:The problem: there's no easy way to conditionally provide an
Optional<Foo>at runtime. This is because there's no equivalent to@ElementsIntoSetfor optional bindings.Workaround
Fortunatelly there's a way to overcome the problem above. We need to replace
@BindsOptionalOf fun optionalFoo(): Foowith:Then, we can conditionally provide an
Optional<Foo>at runtime as follows:Potential solution (feature request)
The workaround above works, but it's far from ideal (e.g. having to use a qualifier, nested optionals, intermediate binding). Ideally I'd like to be able to write something like this:
Would it be possible to implement this feature?