<div dir="ltr">Hi Mike,<div><br></div><div>Thanks for the library. It looks like you&#39;ve done a lot of great hacking on it:</div><div><br></div><div>Dependency injection is a topic near and dear to me. :) I&#39;m very curious about this pattern and its libraries and have been investigating them more deeply lately. I haven&#39;t yet seen the value in this approach (not just in Swift, but in any language), but if you have time and interest I&#39;d be very happy to learn your thoughts (and others&#39;) on why it&#39;s superior to manual dependency injection. I wouldn&#39;t normally do this :), but I&#39;m responding to your invitation: </div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Even would be stoked with a response to the tune of &quot;You don&#39;t need DI in Swift for reasons X, Y, and Z.&quot;</blockquote><div><br></div><div>As an aside, I tried to peek at <a href="https://github.com/square/Cleanse/tree/github-initial-version/Examples/CleanseGithubBrowser">your example app</a> to get more context (it&#39;s linked at the bottom of the &quot;Satisfying Dependencies&quot; section of your README), but it appears missing. </div><div><br></div><div>My first point of confusion is that these libraries seem to be less about dependency injection and more about service location. For instance, in your GitHub example in the playground, we see the following:</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="tahoma, sans-serif">struct GithubListMembersServiceImpl : GithubListMembersService {<br>    let githubURL: TaggedProvider&lt;GithubBaseURL&gt;</font></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="tahoma, sans-serif"> <br></font></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="tahoma, sans-serif">    func listMembers(organizationName: String, handler: [String] -&gt; ()) {<br>        let url = githubURL<br>            .get()<br>            .URLByAppendingPathComponent(&quot;orgs/\(organizationName)/public_members&quot;)<br>        let dataTask = urlSession.dataTaskWithURL(url) ...</font></blockquote><div><br></div><div>To my mind it doesn&#39;t look like githubURL was injected. It looks like it was looked up in a service locator. In fact, it appears that the Binder is a service locator, and you can simply set up multiple service locators for multiple environments (with the added flexibility of multiple types via tags). I call this solving the problem of inflexible global state (usually singletons) by making it a flexible global state (a global service locator).</div><div><br></div><div>I&#39;ve always thought of dependency injection as being a tool for avoiding global state. But in this case it seems to me like the service locator is globally managed. The language of service locators is even present in Guice&#39;s <a href="https://github.com/google/guice/wiki/Motivation">excellent motivation page</a> (my emphasis):</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Guice will inspect the annotated constructor, and <b><i>lookup</i></b> values for each parameter.<br></blockquote><div><br></div><div>Another point I&#39;ve heard people talk about is that these libraries help as dependencies grow. I hope this isn&#39;t a straw man, as I interpret the following line in your README in that way.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">As the functionality of this app grows, one may add arguments to RootViewController and its dependencies as well as more modules to satisfy them.<br></blockquote><div><br></div><div>The argument seems to go that this is easy to maintain:</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="tahoma, sans-serif">init(a: A)</font></blockquote><div><br></div><div>But this is difficult:</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="tahoma, sans-serif">init(a: A, b: B, c: C, d: D, e: E, ...)</font></blockquote><div><br></div><div>The argument goes further by saying that it becomes especially difficult as you may need to pass the dependencies through the some nodes of the object graph that seem not to need them. For instance, in the object graph A -&gt; B -&gt; C, if C has a dependency on Foo but B does not, why should B know about Foo?</div><div><br></div><div>But I find that argument unconvincing on two grounds. First, I believe an object&#39;s dependencies are the union of its and its children&#39;s dependencies. In the example above, B has an implicit dependency on Foo. &quot;Skipping&quot; passing them around or instantiating them in the owning class is actually only hiding an object&#39;s true dependencies by using global state. Second, as a single object&#39;s dependencies become more unwieldy it seems in practice to indicate an architectural problem where objects are doing too much. These problems are related, as the architectural problem may not be as visible when the true dependencies are hidden!</div><div><br></div><div>So to me — and with great respect for the work you&#39;ve done! I know a lot of people (even some of my teammates with Dagger) value this approach immensely — I don&#39;t personally see how the approach adds value over manual injection, and I think the complexity is a negative.</div><div><br></div><div>I do think there is value in aiding with property injection for the cases where we can&#39;t use initializer injection (we do often use storyboards at my company, although we try to keep them small and unwieldy!), but I think those cases are solved with a few clever extensions. See post-script if you&#39;re curious.</div><div><br></div><div>So: I&#39;d love to know what sorts of use cases you find where this sort of library is very helpful.</div><div><br></div><div>Thanks,</div><div>Ian</div><div><br></div><div>For contrast, I&#39;ve been handling property injection on iOS with a few helpers, depending on how I want to do it.</div><div><br></div><div>For segues identified by identifier (at my company we do tend to use storyboards with medium frequency; although we keep them separated into small collections of scenes rather than large unwieldy ones), extensions help create code like this:<br></div><div><br></div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="tahoma, sans-serif">let dependency: Dependency       // itself injected, or</font></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="tahoma, sans-serif">// var dependency: Dependency! // if it could not be injected at instantiation</font></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="tahoma, sans-serif"> </font></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="tahoma, sans-serif">override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {<br>    switch segueFromStoryboardSegue(segue) {<br>    case .GoToCustomViewController(let custom):<br>        custom.inject(dependency: dependency)<br>    }<br>}</font></blockquote></div><div><br></div><div>That&#39;s taken from some experiments I did at <a href="https://github.com/willowtreeapps/segue_handler">https://github.com/willowtreeapps/segue_handler</a><br></div><div><br></div><div>Or in simple cases where I mostly care about type, I can do things like this:</div><div><br></div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><font face="tahoma, sans-serif">override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {<br>    if let custom: CustomViewController = segue.destinationViewController.injectable() {<br>        custom.inject(dependency: dependency)<br>    }<br>}</font></blockquote></div><div><br></div><div>With the extension here: <a href="https://gist.github.com/ianterrell/5aa139ab4b835b85cfee8e0f4430b863">https://gist.github.com/ianterrell/5aa139ab4b835b85cfee8e0f4430b863</a></div><div><br></div><div>Finally, for that style of property injection a precondition in viewDidLoad or before usage in other types can ensure that the inject method was called.</div><div><br></div><div>In my mind the AppDelegate represents the root of my graph, and is generally responsible for setting up all the dependencies it needs to care about. For integration tests or XCUITests (such as I&#39;ve done, which is limited, which might be skewing my opinion), I use environment variables or launch options.</div><div><br></div><div><br></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Jun 14, 2016 at 7:55 PM, Mike Lewis via swift-users <span dir="ltr">&lt;<a href="mailto:swift-users@swift.org" target="_blank">swift-users@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi,<div><br></div><div>I&#39;ve recently open sourced a dependency injection framework for Swift called Cleanse. <a href="https://github.com/square/cleanse" target="_blank">https://github.com/square/cleanse</a></div><div><br></div><div>It does a couple things I&#39;d consider novel with the type system to make wiring up functions easy without having to use reflection or other runtime or compile-time hacks (I tried elaborating on it in this part of the README here <a href="https://github.com/square/Cleanse#dependency-requesting-terminating-methods" target="_blank">https://github.com/square/Cleanse#dependency-requesting-terminating-methods</a>)</div><div><br></div><div>Anyways, I&#39;m looking for feedback on the design and use of this library, and maybe strike up a discussion on language features that may make writing a library such as this be able to be &quot;cleaner&quot; in the future. Couple things that come to mind are custom annotations for qualifying types (instead of what we call &quot;type tags&quot;), variadic generic arguments (which we work around by code generating the various arities), or even a plugin architecture to achieve things similar to what can be done with Java annotation processors.</div><div><br></div><div>I&#39;d also be interested in feedback on some more of the implementation details. e.g. is using this to key objects by type a good thing or a terrible thing? <a href="https://github.com/square/Cleanse/blob/master/Cleanse/TypeKeyProtocol.swift" target="_blank">https://github.com/square/Cleanse/blob/master/Cleanse/TypeKeyProtocol.swift</a></div><div><br></div><div>Since Swift generics don&#39;t seem to be completely understood by the general population, was hoping I could get some concrete feedback here. Even would be stoked with a response to the tune of &quot;You don&#39;t need DI in Swift for reasons X, Y, and Z.&quot;</div><div><br></div><div>Thanks!</div><span class="HOEnZb"><font color="#888888"><div>Mike Lewis</div></font></span></div>
<br>_______________________________________________<br>
swift-users mailing list<br>
<a href="mailto:swift-users@swift.org">swift-users@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-users</a><br>
<br></blockquote></div><br></div>