Retrieving Interfaces (Duck Typing)
Remy can resolve an interface from a concrete implementation you registered, as long as duck typing is enabled in the injector configuration.
This allows you to register concrete types and retrieve them through the interfaces your consumers depend on—no explicit interface bindings required.
Enable duck typing in the injector configuration:
| |
| |
When DuckTypeElements is enabled:
- Remy resolves services by assignability, not only by exact type.
- This allows retrieving an interface (
Warframe) when only a compatible concrete type (Citrine) is registered. - Lookup follows the scope chain upward; the first assignable service is returned.
- This only works per scope injector, if an Injector instance has multiple possibilities to an interface, it will raise an error
The Go proverb “Accept interfaces, return structs” also applies to Remy’s dependency registration:
- Register concrete types (structs).
- Retrieve using interfaces.
This allows Remy to infer assignability and apply duck typing correctly. If you register using an interface as the key, Remy cannot guess other interfaces it might also satisfy later. Duck typing helps when a concrete type is registered and you ask for an interface it implements.
| |
| |
When you register an interface as the key, Remy can no longer infer what other interfaces the concrete type may satisfy.
| |
Tags behave normally with duck typing and are often the best way to disambiguate implementations.
Very broad interfaces (e.g., fmt.Stringer) may match many services.
Use tags to avoid ambiguity. When you intentionally want to work with all matching implementations, prefer the
GetAll-family of functions instead of single-value getters.
Duck typing broadens the search space. Enable it only when needed.
Ensure the concrete type truly satisfies the interface based on receiver type (value vs pointer).
Check that:
DuckTypeElementsis enabled.- The concrete type implements the requested interface.
If more than one implementation matches, you have two main options:
- Add unique tags on registration and use those tags when retrieving a single value, or
- Use the GetAll family to retrieve the full set of matching implementations:
// Retrieve all matching services
encoders := remy.MustGetAll[Encoder](inj)
for _, enc := range encoders {
_ = enc.Encode([]byte("payload"))
}
Resolution walks up the parent chain; the first assignable service is returned.
Config.DuckTypeElements: enables interface-to-implementation duck typing.Config.ParentInjector: enables parent lookup when using hierarchical injectors.