Skip to content
This repository has been archived by the owner on Sep 16, 2022. It is now read-only.

RFC: Compile-time dependency injection. #364

Closed
matanlurey opened this issue Apr 27, 2017 · 5 comments
Closed

RFC: Compile-time dependency injection. #364

matanlurey opened this issue Apr 27, 2017 · 5 comments

Comments

@matanlurey
Copy link
Contributor

We'd like an Angular application to be able to use almost entirely compile-time dependency injection (no runtime checks or lookups). We'll need to be able to make more closed-world assertions about the state of your application and remove or deprecate parts of the API that make this impossible (and de-optimize in those cases).

The result is just a series of get() calls across your application:

class Bootstrap$Injector implements Injector {
  Foo _fooService;

  @override
  get(token) {
    switch (token) {
      case Foo: 
        return _fooService ??= new Foo();
      default: 
        return noProviderFound;
    }
  }
}

class RootComponent$View {
  RootService _rootService;

  @override
  injectorGet(token) {
    switch (token) {
      case RootService:
        return _rootService ??= new RootService();
      default:
        return super.inejctorGet(token);
    }
  }
}

Deprecated

  • ReflectiveInjector: This relies on using the static Reflector to find and create arbitrary classes from previously generated factories.

Possible replacements:

  • MapInjector
  • Some sort of additional code generation in an @Component:
@Component(
  selector: 'comp',
)
class Comp {
  @Resolve(const [ ... ])
  set injector(Injector generated) { ... }
}
  • Using bootstrap(<root component>, <providers>). We need to resolve at compile-time:
@Bootstrap(RootComponent, const [
  // Providers go here.
])
void main(Bootstrapper<RootComponent> bootstrap) {
  bootstrap();
}
  • Using provide(), just T (type), or new/const Provider() (with multiple optional parameters):

    • const Provider<Foo>()
    • const Provider<Foo>.useExisting(AbstractFoo)
    • const Provider<Foo>.useClass(FooImpl)
    • const Provider<Foo>.useFactory(createFoo)
    • const Provider<Foo>.useValue(const Foo())
  • Replace OpaqueToken with InjectionToken:

const baseUrl = const InjectionToken<String>(#baseUrl);

/// Now can `@Inject<String>(baseUrl)`
const Provider<String>.useValue('Hello World', token: baseUrl);
  • Using Provider(multi: true). Not sure about replacement yet!

/cc @alorenzen.

@yjbanov
Copy link
Contributor

yjbanov commented Apr 28, 2017

remove or deprecate parts of the API that make this impossible (and de-optimize in those cases)

Sorry for pedantry, but I'm a little confused by this part. If conflicting APIs are to be removed, why the need to de-optimize in those cases if there won't be such cases any more? Did you mean "remove or de-optimize"?

return super.inejctorGet(token);

RootComponent$View is direct descendant from Object, so there's no super.injectorGet.

@Bootstrap

Why not reuse the existing @AngularEntrypoint?

@matanlurey
Copy link
Contributor Author

matanlurey commented May 11, 2017

No problem re-using @AngularEntrypoint :)

Sorry for pedantry, but I'm a little confused by this part. If conflicting APIs are to be removed, why the need to de-optimize in those cases if there won't be such cases any more? Did you mean "remove or de-optimize"?

Yes, I meant remove or de-optimize. Thanks!

@chalin
Copy link
Collaborator

chalin commented May 12, 2017

Good proposal. I just have one comment about a suggested class definition for InjectionToken : see #288 (comment).

@matanlurey
Copy link
Contributor Author

This will not be in 4.0.0, but I am looking at getting in part of the API:

  • Using provide(), just T (type), or new/const Provider() (with multiple optional parameters):
    • const Provider<Foo>()
    • const Provider<Foo>.useExisting(AbstractFoo)
    • const Provider<Foo>.useClass(FooImpl)
    • const Provider<Foo>.useFactory(createFoo)
    • const Provider<Foo>.useValue(const Foo())

So I've opened #407.

@matanlurey
Copy link
Contributor Author

Thanks everyone for your feedback. A summary of accepted ideas is now here:

https://github.com/dart-lang/angular/projects/4

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants