fluttercommunity / get_it

Get It - Simple direct Service Locator that allows to decouple the interface from a concrete implementation and to access the concrete implementation from everywhere in your App. Maintainer: @escamoteur
https://pub.dev/packages/get_it
MIT License
1.34k stars 145 forks source link

GetIt not being able to correctly find registered Type #222

Closed AlvBarros closed 2 years ago

AlvBarros commented 3 years ago

Hey all!

Sorry if this issue is in the wrong format, I didn't find anything mentionind any guidelines on how to write one.

My app has this issue where I can't get my instance after registering. Through some deep debugging, I've found this method "_findFirstFactoryByNameAndTypeOrNull" inside get_it_impl.dart that compares the given T to a scope's factoriesByName, and this comparison by Map index wasn't working properly.

In other words; when I run the line:

final AuthenticationService authService = GetIt.I.get<AuthenticationService>(instanceName: "authentication");

After a while, the package goes through its factories in its scope.

while (instanceFactory == null && scopeLevel >= 0) {
      final factoryByTypes = _scopes[scopeLevel].factoriesByName[instanceName];
      if (type == null) {
        instanceFactory = factoryByTypes != null
            ? factoryByTypes[T] as _ServiceFactory<T, dynamic, dynamic>?
            : null;
      } else {
        /// in most cases we can rely on the generic type T because it is passed
        /// in by callers. In case of dependent types this does not work as these types
        /// are dynamic
        instanceFactory = factoryByTypes != null
            ? factoryByTypes[type] as _ServiceFactory<T, dynamic, dynamic>?
            : null;
      }
      scopeLevel--;
    }

But when I compare on debug:

Captura de Tela 2021-08-17 às 14 03 53

Am I doing something wrong?

AlvBarros commented 3 years ago

Here is my flutter doctor:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.2.3, on macOS 11.4 20F71 darwin-x64, locale pt-BR)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.2)
[✓] VS Code (version 1.59.0)
[✓] Connected device (2 available)

Here is my flutter --version:

Flutter 2.2.3 • channel stable • https://github.com/flutter/flutter.git
Framework • revision f4abaa0735 (7 weeks ago) • 2021-07-01 12:46:11 -0700
Engine • revision 241c87ad80
Tools • Dart 2.13.4

I'm using get_it version 7.2.0, running on macOS Big Sur.

omerrciftcii commented 3 years ago

I have same problem with get_it 7.2.0, instanceFactory != null error has occurs. Did you find any solution for this? Eveything seem correct in my code. Here is my question in stackoverflow: https://stackoverflow.com/questions/68742643/when-i-try-to-inject-dependencies-an-error-has-been-occurs-which-says-failed-a

escamoteur commented 2 years ago

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

this seems indeed strange. Does anyone of you have a short repro project?

royd commented 2 years ago

@escamoteur I can repro here on the flow branch. Repro steps:

  1. Run app
  2. Click "Collect Sequence"
  3. Enter a number and click "Accept"
  4. Assertion
royd commented 2 years ago

The issue for me was with the improper capitalization of the import here.

package:architecture/flow/import_seed/screen2/screen2_bloc.dart was registered. But.. package:architecture/flow/import_seed/Screen2/Screen2_bloc.dart was requested.

It compiled, but the hash code in the factoryByTypes map was different from the requested type T.

escamoteur commented 2 years ago

Also, does this happen on all Platforms?

escamoteur commented 2 years ago

For all others in this thread, can you check if you too might have different capitalization in your imports?

escamoteur commented 2 years ago

@leafpetersen to me this looks like a compiler bug if types get different Hashcodes depending on how the import is capitalised

royd commented 2 years ago

I see the same behavior on ios, macos, and web.

escamoteur commented 2 years ago

did you try to make a really simple project without get_it and compare the Hashcodes of the types if the imports differ? That would be really helpful and if yes you could directly report it to the dart team

royd commented 2 years ago

Here is a basic repro:

import 'one.dart' as lower;
import 'one.dart' as lower2;
import 'One.dart' as upper;

void main() {
  final a = lower.One;
  final b = lower2.One;
  final c = upper.One;

  print("a: ${a.hashCode}");
  print("b: ${b.hashCode}");
  print("c: ${c.hashCode}");
}

where the file one.dart contains

class One {}

which yields:

% dart run main.dart                   
a: 830824423
b: 830824423
c: 886268188

Interestingly, now VS Code is giving me a red line under 'One.dart', though it wasn't before, and though it still compiles.

leafpetersen commented 2 years ago

I believe you're running into a known sharp edge around non-canonical URIs. Basically, if you import a file twice with a different URI, Dart treats the two imports as entirely unrelated things, as if you'd made two copies of the file and imported them separately. So in your example above, lower.One and upper.One are treated as two entirely unrelated types from unrelated libraries that just happen to have the same name. You can see this by trying to assign one to the other: if you add the line lower.One one = upper.One(); to your test, you'll get a static error. There is an request here for a hint to warn about this when possible.

cc @natebosch @lrhn in case I'm missing something else going on.

escamoteur commented 2 years ago

I recall that we had the same situation some time ago when you mixed package and relative imports that were solved so that these imported types were treated equally.

Why does Dart treat import filepaths caps-sensitive when it doesn't make any sense on non Unix like platforms?

lrhn commented 2 years ago

Dart identifies libraries by their import URL. Different capitalization makes it different URLs, even if they happen to resolve to the same local file. Library identification is case sensitive, because URLs are, independently of the underlying file system. (If there is a file system at all, originally you could import using http: URIs too). What you remember is that package: URI imports are considered different from file: URI imports, even if both resolve to the same local file, a problem which has even more impact if such a double-imported library has relative imports of its own. We had a fix for one case of this: When a file in the lib/ directory was passed as entry point on the command line, we treat it as the corresponding package: URI.

The problem with case is that it's not generally true that foo.dart and Foo.dart is the same file (only on Windows, but that means that it's also not generally true that they are different files.) I think the best we can do is to warn if something looks like it's probably a mistake.

escamoteur commented 2 years ago

Hmm, OK, because Linux treats the paths differently you can't even just make the import lowercase because you could access the real file no longer. But a warning is definitely necessary. Windows developers are not used to think about capitalisation in paths Am 5. Feb. 2022, 19:08 +0100 schrieb Lasse R.H. Nielsen @.***>:

Dart identifies libraries by their import URL. Different capitalization makes it different URLs, even if they happen to resolve to the same local file. Library identification is case sensitive, because URLs are, independently of the underlying file system. (If there is a file system at all, originally you could import using http: URIs too). What you remember is that package: URI imports are considered different from file: URI imports, even if both resolve to the same local file, a problem which has even more impact if such a double-imported library has relative imports of its own. We had a fix for one case of this: When a file in the lib/ directory was passed as entry point on the command line, we treat it as the corresponding package: URI. The problem with case is that it's not generally true that foo.dart and Foo.dart is the same file (only on Windows, but that means that it's also not generally true that they are different files.) I think the best we can do is to warn if something looks like it's probably a mistake. — Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you were mentioned.Message ID: @.***>