square / Cleanse

Lightweight Swift Dependency Injection Framework
Other
1.78k stars 90 forks source link

Swift Package Manager issue #123

Closed ultraon closed 4 years ago

ultraon commented 4 years ago

Hello, thanks for this amazing library. I have an issue with adding the library as a dependency using Swift Package Manager in Xcode 11.3

Error message:

The package dependency graph can not be resolved; unable find any available tag for the following requirements:

https://github.com/square/Cleanse — 4.2.4..<5.0.0

I think the format of Package.swift should be updated.

sebastianv1 commented 4 years ago

Thanks for reporting! Unsure why this is happening atm. Will look into this. Is there anything we can do to help unblock consuming?

ultraon commented 4 years ago

@sebastianv1 Thanks for the response. I'm wondering when Cleanse have Swift Property Wrappers related functionality, it could be very similar to Dagger 2 using Inject annotations https://docs.swift.org/swift-book/LanguageGuide/Properties.html .

sebastianv1 commented 4 years ago

This is going off topic from the original issue you filed (still going to investigate), but why not diverge a bit :)

I'm happy you asked about Cleanse and property wrappers! I've been thinking a bit about this and would love to hear your input. First, although Java annotations and Swift Property Wrappers look similar leveraging the @ character, they function very differently. From Java's docs:

Annotations do not directly affect program semantics, but they do affect the way programs are treated by tools and libraries, which can in turn affect the semantics of the running program.

Swift property wrappers have direct effects on how your program functions. I think the Swift team did a good job with the naming since they are exactly that: just a wrapper around properties to help reduce duplicated operations and provide some nice syntactic sugar. Today, the closest thing we could turn into a property wrapper for Cleanse would be a Provider<Element>. Java annotations can be used on many different language primitives like functions, properties, and classes. This feature has allowed DI frameworks like Guice and Dagger to parse the code metadata and discern which services the developer wants to inject. Cleanse operates a little differently, mostly because of language constraints, by specifying which services you would like to inject in a separate container (within the binder functions) outside of your object's constructor.

I'm curious on your take and use case for property wrappers with Cleanse. How would you use them and what benefit would this give you? I've seen discussions how it could help make it more explicit that something is being injected by a DI framework to make things feel less magical since DI frameworks are pretty magical. I could see this being the case, but if so then I feel like we would have to change Cleanse to only accept types of the property wrapper (say Inject<Element>, AKA @Inject var service: Element), otherwise your code could end up in a state with mixed @Injects and normal properties that are being injected in the same way, creating way more confusion.

Cleanse's role in the world is to take your bindings and inject the dependencies you request for each object. We don't do anything special with the services except store them in a fancy dictionary and vend them to you. I don't see a case where using property wrappers gives you any tangible benefit aside from @Provides var service: Service looking a little cleaner than let service: Provider<Service> (also note that property wrappers must be a var even if the backing wrappedValue is get-only).

I see that Swinject is supporting property wrappers, but in order to leverage this feature you would have to make your object conform to a new protocol and inject their Resolver object. This feels worse overall because it ruins the "purity" of your classes in sense that your classes are now aware of some sort of DI container. Reusing that object in a non-DI framework world now becomes impossible, and makes unit testing that object much more difficult.

sebastianv1 commented 4 years ago

@ultraon Released v4.2.5 which should allow you to add Cleanse as a Swift PM dependency. Verified it worked locally on XC 11.2.1. Let me know if you run into any more issues.