Swinject 3.0

Created on 25 Jul 2019  路  8Comments  路  Source: Swinject/Swinject

Motivation:

New features which are difficult to add in the current status quo. To name a few:

  • multitons (#254)
  • base class registration (#108)
  • collection resolution (#271)

Frequent issues mostly related thread safety, and inherently suboptimal concurrency model

API enhancements: There are a lot of itches with the current API that have been recurring over and over again:

  • explicit specification of the resolved type (#229)
  • cumbersome handling of missing dependencies (#358)
  • inflexible parent-child container relationship (#80)
  • unintuitive resolver synchronization
  • no type checking for type forwarding (#339)
  • inflexible scoping model compared other DI frameworks out there
  • instance retrieval (#365, SwinjectStoryboard)

New language features: Swift 5's @functionBuilder & @propertyWrapper offer a lot of new options to the API design.

Roadmap

  • [ ] Define the 3.0 API for the core DI functionality
  • [ ] Reimplement the core functionality
  • [ ] Refactor current API to use the new DI "engine"
  • [ ] Add reasonable interoperability between new & current API
  • [ ] Craft new documentation
  • [ ] Release Swinject 3.0 with dual API
  • [ ] ...
  • [ ] Drop legacy API in Swinject 4.0

Status

Work on the first three milestones has begun in the Swinject/3.0 branch, things are still very open to the design changes. Idea of the new API is described here.

All input, ideas & critique is appreciated 馃槈 We can discuss it here or on Swinject's Slack

Most helpful comment

Current implementation of the 3.0 API should support all these scenarios:

All 8 comments

I would really appreciate support for throwing resolve() methods, as in #358. I've already built wrappers around this myself that I'd be happy to turn into a PR if you are interested.

Also, I'd like to see better support for injecting dependencies that have a throwing initializer. If resolve is throwing and the initializer for the registered object throws, I'd like to get that error.
And also optional initializers. I might be missing something, but I currently see no way to register a dependency with an optional initializer.

@AnthonyMillerSF
Best approach seems to be to make API methods throwable by default - from that it is easy to do try? resolve() or try! resolve(). That should seamlessly handle throwing initializers.

Optional initializers are a bit tricky - I see 2 potential ways to handle them

  1. convert them to throwing initializers (either implicitly, or explicitly by something like .orThrow())
  2. Enable registrations for Optional<Type> to be used when resolving non-optional Type, and throw appropriate error if underlying initializer returns nil

Best approach seems to be to make API methods throwable by default - from that it is easy to do try? resolve() or try! resolve(). That should seamlessly handle throwing initializers.

That's exactly what I'm doing currently. I wrote a wrapper around the current resolve() methods. It works very well. But for registering objects that have a throwing initializer, my wrapper won't work because the register() method takes in a non-throwing closure currently. I'd like to make that closure rethrowing.

For optional initializers, I think that if they return nil, then resolve() should throw an error.

Current implementation of the 3.0 API should support all these scenarios:

You are a hero! Any idea on release schedule?

Also, I'd really love to have #108 (base class registration) in the new version. It looks like it was closed unresolved. Are we not including that in Swinject 3.0?

Hi @jakubvano It's been a while since I've passed by as I've been off working on other projects (some of which could really benefit from Swinject). Just wanted to say thanks for all the great work and the new features. Looks like some really good stuff be added and a great vision for the future.

ciao
Derek

I think you need to remove Provider, Lazy injection to remove Swinject dependency on target classes.
I suggest using a new factory-provider API as the Kodein:

class Something {
    init(dependency: (Int) -> Dependency) {
        let dependency1 = dependency(1)
    }
}

bind<Something> {
    Something(factory())
}
Was this page helpful?
0 / 5 - 0 ratings