get_it icon indicating copy to clipboard operation
get_it copied to clipboard

[Question] GetItAll from one type?

Open rafaelcorbellini-egsys opened this issue 5 years ago • 63 comments
trafficstars

Is there any way to get everyone of a kind?

example when logging out of the application I want to get all objects registered as DAO and perform a function of them.

rafaelcorbellini-egsys avatar May 05 '20 11:05 rafaelcorbellini-egsys

You mean you registered multiple instances of the same type? and you want to call the same method on all of them?

escamoteur avatar May 11 '20 13:05 escamoteur

I want get all instance of one type.

Example i have N InterfaceDAO (UserDao, TodoDAO... ) and register all of them.

have some way to resolve all (Iterable<InterfaceDAO>) registered ?

rafaelcorbellini-egsys avatar May 14 '20 16:05 rafaelcorbellini-egsys

ah, understood. I will think about it.

escamoteur avatar May 27 '20 14:05 escamoteur

@escamoteur Have you analyzed this topic? Are there any real chances to implement this?

mareklat avatar Feb 19 '21 12:02 mareklat

Could you elaborated why this would be useful?

escamoteur avatar Feb 22 '21 09:02 escamoteur

Of course. Most of all, it helps to write modular and clean code.

For example: I have an Interceptor interface in my http client. In the object responsible for communication with the server, I inject a list of objects implementing the Interceptor interface. Then, when I want to add a new Interceptor, just only create a new implementation.

A similar solution is present in other DI libraries, e.g. Dagger, Spring Boot, etc.

mareklat avatar Feb 23 '21 14:02 mareklat

One question would be should it only get all of exact the same type or also derived types?

escamoteur avatar Feb 24 '21 08:02 escamoteur

I think they should it only get all of exact the same type. We can use type passed when there are registering factory, for example

getit.factory<Interceptor>(() => LoggingInterceptor());

Currently, when I register more than one object with the same type and when allowReassignment==false , the library throws an exception. Instead, we could register a collection of interfaces

getit.factory<List<Interceptor>>(() => [
   get<LoggingInterceptor>(),
   get<AnotherInterceptor>(),
   ...
]);

Maybe new flag will be necessary to allow binding into collection.

mareklat avatar Feb 24 '21 13:02 mareklat

ok, makes sense, but I need to find time for it. Still not finished to convert all my pacakges to null safety

escamoteur avatar Feb 24 '21 13:02 escamoteur

Fantastic :) I haven't explored the get_it internal yet, but in my free time I'll try to help

mareklat avatar Feb 24 '21 13:02 mareklat

@escamoteur Hey, have you found the time to focus on this idea? Can we reopen this topic? I believe that this is a crucial and much needed feature

mareklat avatar Jun 11 '21 13:06 mareklat

OK,

your PR used a special intoSet parameter. But do we need this if we can use names instances? You want to be ablt to do a .getAll<Type>() right? If we limit it to the exact type I would probably only have to make a smal change to the internal get_it data structure. But my feeling is we should be able to request all of one type plus derived types to really allo full flexibility

escamoteur avatar Jun 12 '21 12:06 escamoteur

Yes, I agree that the ability to call derived types should remain.

I have a few ideas, but most of it comes to idea where firstly we register instance in the same way as it is now, and optionally bind it to list of parent types.

Normally we can register instance like this: getIt.registerFactory(() =>UserDTO())

But if we want to also register instance to collection of supertypes we can call like this:

getIt.registerFactory(() =>UserDTO()).inToList<DTO>();

and in some point in code:

getIt.get<List<DTO>>()

To allow this behavior, each registration method must return an object. An object that allows you to call the inToSet method. An example of this object:

class Multibinding<T extends Object> {

  final GetIt _getIt;

  Multibinding(this._getIt);

  void inToList<S>() {
    if (!(T is S)) {
      throw "$T is not subtype of $S";
    }

    if (_getIt.isRegistered<List<S>>()) {
      List<S> list = _getIt.get();
      _getIt.unregister<List<S>>();
      _getIt.registerFactory<List<S>>(() {
        T instance = _getIt.get();
        var newList = list.toList();
        newList.add(instance as S);
        return List.unmodifiable(newList);
      });
    } else {
      _getIt.registerFactory<List<S>>(() {
        T instance = _getIt.get();
        var newList = <S>[];
        newList.add(instance as S);
        return List.unmodifiable(newList);
      });
    }
  }

}

I think this solution allows you to implement multibinding concept with a minimum amount of work. What do you think?

mareklat avatar Jun 14 '21 11:06 mareklat

not sure if we need that.

if we add an

List<MyType> = getIt.getAll<MyType>();

that returns you all registered objects with that type and its derived types.

escamoteur avatar Jun 14 '21 12:06 escamoteur

Hmm.. this will be much better to use. In this approach when we call getAll<SuperType>(), we need scan all factories and compare like T is SuperType, collect them to list and return. This will be efficient?

mareklat avatar Jun 14 '21 12:06 mareklat

Yeah this might not be very performant. But I try to imagine how often will you have to do such a call? It's probably nothing you do on every frame. it's O(n) which means even if you have registered 1000 objects it shouldn't take long

escamoteur avatar Jun 14 '21 12:06 escamoteur

I would say lets implement it like that and see what the feedback is

escamoteur avatar Jun 14 '21 12:06 escamoteur

would you try a PR?

escamoteur avatar Jun 14 '21 12:06 escamoteur

You're right, maybe it's not such a bad idea. Ok, I will prepare a PR and we will see :)

mareklat avatar Jun 14 '21 12:06 mareklat

please don't forget adding the new function to the readme

escamoteur avatar Jun 14 '21 12:06 escamoteur

@mareklat I am working with a similar stuff here, your PR will be very appreciated :D About O(n) problem, I suppose it can be resolved with a getAll<SuperType, DerivadType?>() ?

ernesto avatar Aug 09 '21 16:08 ernesto

IMO there is two separate API calls:

  • getAll<ExactType>()
  • getAllWithSubtypes<SuperType>()

Our practice with Dagger and Guice (Android and backend) shown that first call is sufficient in 90%+ cases. Actually I found 4 cases out of few hundred in all accessible projects where with subtypes lookup is used. For SOLID-complied code that case is very uncommon if possible at all.

So I propose implement '10 for 90' case with just getAll<ExactType>() and see on feedback to implement withSubtypes case.

About O(n) complexity - for most practical graphs (<1000 bindings) is not measurable impact on app performance.

vladimirfx avatar Oct 16 '21 14:10 vladimirfx

Hi, sorry for not looking into this earlier, but I had some mental health problems the last half year.

No PR has appeared yet. let me see if I find the time to add it

escamoteur avatar Feb 02 '22 11:02 escamoteur

I think a use case like clearing/resetting all the DAOs/ViewModel objects when a user log out can be done by using something like the Pub-Sub pattern instead.

iandis avatar Jun 14 '22 13:06 iandis

Also let's say I've registered some factories in get it and they all implement IFactory interface. Now I want to write some kind of factory selector and it would be perfect for me to get all factories and then select the appropriate one.

0ttik avatar Nov 30 '22 19:11 0ttik

Hey guys, sorry for revive this topic, but is there any plan to implement this feature?

brunogabriel avatar Dec 16 '22 04:12 brunogabriel

What I really enjoy using Autofac, is how they handle multiple with the As<> binding. You register an instance not only as itself, but also as a specific interface.

Requesting for this interface could return multiple instances or only one.

GetIt.I.register<Foo>(Foo()).As<IFoo>();
GetIt.I.register<Bar>(Bar()).As<IFoo>();

var allFoos = GetIt.I.getAll<IFoo>();

I know that Autofac is a dependency injection framework, but for me something similar could work here as well. I found another package called needle, that seems to do something similar but it hasn't been developed for over 2 years.

The interesting part for me here is that they return some kind of RegistrationBuilder class that again has more functions to work with to complete the registration.

I have not looked into the GetIt code base, but I can imagine that this would require quite some refactor.

praxamarnix avatar Jan 27 '23 11:01 praxamarnix

What I really enjoy using Autofac, is how they handle multiple with the As<> binding. You register an instance not only as itself, but also as a specific interface.

Requesting for this interface could return multiple instances or only one.

GetIt.I.register<Foo>(Foo()).As<IFoo>();
GetIt.I.register<Bar>(Bar()).As<IFoo>();

var allFoos = GetIt.I.getAll<IFoo>();

I know that Autofac is a dependency injection framework, but for me something similar could work here as well. I found another package called needle, that seems to do something similar but it hasn't been developed for over 2 years.

The interesting part for me here is that they return some kind of RegistrationBuilder class that again has more functions to work with to complete the registration.

I have not looked into the GetIt code base, but I can imagine that this would require quite some refactor.

you are aware, that you can do exactly that if you pass your interface type as the generic parameter?

GetIt.I.register<IFoo>(Bar());

escamoteur avatar May 08 '23 10:05 escamoteur

Any movement on this? It's a pretty crucial feature if you want to have a module based architecture

hughesjs avatar Feb 11 '24 17:02 hughesjs

Passing an additional interface type is an interesting idea. Would make it easy to implement it performant. They get_it is currently implemented, getting all implentations of one type wouldn't be fast as I would have to go through all registrations. Passing an optional interface type when registering would be a clear signal to save a reference to that type parallel to the normal registration.

Am 11. Feb. 2024, 18:52 +0100 schrieb James H @.***>:

Any movement on this? It's a pretty crucial feature if you want to support plugins... — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you modified the open/close state.Message ID: @.***>

escamoteur avatar Feb 11 '24 18:02 escamoteur