Did you ever check out watch_it?
Yes. I used it for a long time. But, when things begin to grow, get_it get in the way (pun intended).
It seems Dart has no dependency injection framework available (which makes sense, given its lack of introspection, something that is really needed for DI to work, adding the slooooooooowness of build_runner to that).
Service locators works, but when you have a big project with a lot of dependencies (and those are scoped), well, things get ugly very fast. No dart library handles registration order or circular dependencies (I don’t expect the tool to fix that for me, but at least warn me “hey, you messed up”) I guess because Dart is very limiting as a language to build tools (lack of introspection, lack of runtime information (for instance, which interfaces this class implements?), etc.) You can’t even build a class given its type >.<
One thing I really miss about watch_it is the ability of rebuilding only when a property of a ChangeNotifier changes. But, after I saw this, it just drop my confidence in it: Gradual Performance Degradation using watchPropertyValue on ChangeNotifier Member · Issue #32 · escamoteur/watch_it · GitHub
It seems like the best feature is not used by the author… wait… are you the owner of watch_it? O.o
* awkward moment *
So, how is the weather?
* try to change subject *
Actually tat issue got fixed a while ago. And it does exactly what you want.
Good to know.
I also highly recommend using it together with flutter_command.
Hmmm… Nice package, it remembers me the actual MVVM Command from XAML (just a bit more complicated). I like it.
Would love to get more input about how we could improve the registration process.
My issue was the amount of choices. For some things, I must use registerSingletonAsync, so then it complains that another dependency is not async singleton, then I need to change that, then it broke things in other places… I always feel like I’m disarming a bomb using get_it =(
Also, when I read dependsOn
, my mind reads “dependencies that this dependency depends on”: it would be smart enough to initialize stuff in the correct order, but it actually doesn’t use dependsOn
whatsoever O.o I don’t get why. For instance:
GetIt.I.registerSingletonWithDependencies<Interface2>(
() => Class2(GetIt.I<Interface1>()),
dependsOn: [Interface1],
);
GetIt.I.registerSingleton<Interface1>(Class1());
This will fail, because, even if the first registration is a factory, it will fail because the second registration is not there! This doesn’t make any sense (reading the docs now, because I wrote the code above as an example, trying to remember what I did in my projects some months ago, I see that dependsOn
is about initialization, not dependency). But, even so, if the first registration is a factory, it does NOT need to be instantiated in that time and give me an error. It should behave like registerLazySingleton
. It’s not intuitive at all, and now I have another way to register singletons >.< Too much.
I come from C# world (since 2002), so, I like simplicity:
-
You either register a singleton, a scoped or a transient (it’s about intent, not implementation details, it abstracts for me).
-
Then, you don’t need to to anything, except to use it, as you would use in any other class.
For 1) to work, get_it should have to:
a) register dependencies in any order and do a topology search to resolve the dependencies of a dependency.
b) have a build method to do a) above (in which case, that isFinal
property in scope would make much more sense).
c) Be compatible or be Flutter-friendly (i.e.: use the widget tree, not exclusively, but additional to working with Dart alone, which IS a plus). Why? To make scoped registration possible. A scoped registration in C# ASP.net is a singleton for the duration of request. For Flutter, a scoped registration would be a singleton during the duration of a widget present in the tree (i.e.: when the widget that register the scope is disposed, so is the scoped instance and the next resolve would be a new instance).
For 2) to work, we would need macros, unfortunately. Dart is not capable of injecting parameters in constructors or properties and/or methods in classes. I know there is a helper for get_it that uses build_runner, but it eventually gets in the way the same way get_it (I need to change the type of attribute to change the registration code and we get back to that issue about changing from a singleton to a singleton async and breaking other stuff.)
For me, tools need to be smart. If I am the one who needs to be smart, then I’m fucked, because I am not.
To get_it be smart, it would need to be simpler (a singleton is a singleton, you deal with dependencies of dependencies, initialization, disposing, if it needs initialization or not, etc.). But, changing it now would break it, so, it is impossible. And that resumes pretty much why I try to use as little packages possible… they always have some issue, and I’m pretty locked in what I chose to use =\
Programming, for me, is about patterns. Dependency injection is kinda like a philosophy: it’s a guide for something and it establishes some jargon: transient, singleton, scoped. It does not tell how to do that, it only tells you that those kind of dependencies exist and each one serve its own purpose. When the tool ask ME to do more than that, then, I’m working for the tool, and it should be the other way around: DI is an abstraction, get_it should be an implementation. But it is not! I need to be very careful and very aware of how it works so I can write code that satisfy the package needs and biases.
Am I making any sense?