Open shtlrs opened 2 months ago
Hi.
but one issue i faced a lot is registering 2 or more different implementations of the same interface.
Inject is specifically designed to represent an application is a typed object graph. It simplifies reasoning about the whole application.
This can turn out to be useful for example when introducing abstractions in the form of chains of responsibility.
Please, take a look at the example in this comment https://github.com/ivankorobkov/python-inject/issues/104#issuecomment-2141168883
Also, it should be possible to make named registrations of instances of the same interface
In my opinion, it imitates different types in a custom way. It is usually better to just create different types for different use cases.
Hi 👋
Inject is specifically designed to represent an application is a typed object graph. It simplifies reasoning about the whole application.
I get the idea, but when we talk about typed object graph, does it imply that a node can have one child only ?
Please, take a look at the example in this comment https://github.com/ivankorobkov/python-inject/issues/104#issuecomment-2141168883
I did check that, but it's confusing to do that for different reasons:
In my opinion, it imitates different types in a custom way. It is usually better to just create different types for different use cases.
Sure, but i still believe it could use a type binding too. Like, I want this implementation of that interface, but now that I think of it, I am guessing this could be done with the params
decorator.
class Interface(ABC):
def method(self):
pass
class ImplementationX(Interface):
def method(self):
pass
@injector.params(param=ImplementationX)
def somefunc(param: Interface)
param.method()
...
does it imply that a node can have one child only
It does imply that a single type has a single implementation.
The fact that you don't configure the injector is confusing, at least IMO.
There is no need to configure a binding of MyType
to MyType
, inject
can just instantiate it for you without any custom bindings.
Take a look at this case:
@injector.autoparams()
def somefunc(service: MyService)
You already specified that you need MyService
. Inject
can instantiate a singleton for you.
Like, I want this implementation of that interface, but now that I think of it, I am guessing this could be done with the params decorator.
@injector.params(param=ImplementationX)
def somefunc(param: Interface)
That's exactly not an implementation but another type:
@injector.autoparam()
def somefunc(param: InterfaceX)
And that's the idea. Just use the types to specify the whole application as a typed object graph.
There is no need to configure a binding of MyType to MyType, inject can just instantiate it for you without any custom bindings.
Yes, but it needs to be able to know how to instantiate it, not all constructors won't take params.
That's exactly not an implementation but another type: It does imply that a single type has a single implementation.
Aren't both of these contradictory ?
It's theoretically a type yes, but it's used as in implementation (I forgot the @abstractmethod)
Yes, but it needs to be able to know how to instantiate it, not all constructors won't take params.
Good point. In a typical application the only thing that needs to be provided is a configuration instance. All other params are part of an object graph. And the configuration can be bound manually.
Aren't both of these contradictory ?
It just means that a type is what others use and depend on, an an implementation is an actual hidden, private implementation of the type.
Just a random image from google:
Type is an external circle around a dot, which is an implementation. And the whole graph is an application.
Type is an external circle around a dot, which is an implementation. And the whole graph is an application.
Ok, I understand that.
However, what happens when the type needs to be polymorphic, and i need to use different implementation of it based on specific context ?
Meaning, if i have this application like this
How can implementations C
and D
use different implementations of the X
type ? The idea is mainly to register two implementations A
and B
of type X
, it doesn't make much sense to me to create a different type for it.
Simple example:
class Cache:
pass
class MemCache(Cache):
pass
class RedisCache(Cache):
pass
# Later
class UserService:
cache = inject.attr(Cache)
class MailService:
cache = inject.attr(RedisCache) # not named cache "redis"
# Bindings
def configure(binder):
binder.bind(Cache, MemCache())
I think the issue title says it all, but one issue i faced a lot is registering 2 or more different implementations of the same interface.
This can turn out to be useful for example when introducing abstractions in the form of chains of responsibility.
Just like middlewares work for example in web frameworks, you have multiple middlewares and then we iterate on them and each one handle the request per the same interface.
Also, it should be possible to make
named
registrations of instances of the same interface, so that when you need a particular instance that you define based on some key, you can get it from the container.This is possible in frameworks like Autofac or SimpleInjector.