<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Thu, Nov 2, 2017 at 12:41 PM Jon Shier <<a href="mailto:jon@jonshier.com">jon@jonshier.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><span class="m_-2968819130997084382Apple-tab-span" style="white-space:pre-wrap">        </span>This isn’t an argument against Result, it’s an argument against all error encapsulation in Swift at all. Which is fine for your personal project, but frankly I don’t see it as a bad thing as a language capability. Like any other use of type-inference, the compiler guarantees you can’t use the value of the function directly but must go through the Result value to get it, which serves as the indication of there being an error there. Given the usage of Result in the Swift community, I’m thinking your concerns aren’t shared by the vast majority of Swift users. It’s entirely possible for something to exist in the language and have it not be recommended as the default implementation for something. For example, if/guard let are usually recommended over map or flatMap’ing Optional, but the capability exists because it’s very useful when the recommended pattern breaks down. Result is no different.</div></blockquote><div><br></div><div>Optional<>.flatMap isn't the same, because the *API being consumed* isn't what's changing—only how one chooses to consume it. It doesn't matter if you use if-let/guard-let or .flatMap, the type you're dealing with is still Optional<>. APIs that need something optional use Optional<>, period.</div><div><br></div><div>Result<>, on the other hand, opens the door to bifurcating the API space into those that are throwing and those that are Result-returning, when they're trying to convey the same information. Sure, there are explicit functions to transform Result to throwing and vice-versa, but it's still something that forces certain decisions on API consumers. Code that consumes thrown errors vs. code that handles Result-return values will look different and inconsistent depending on which technique the API designer chose. That's not ideal.</div><div><br></div><div>The proposal states the premise that Result<> is commonly desired and popular and is therefore a good fit for the standard library. Aside from its popularity, however, the only use case mentioned is asynchronous APIs—but the proposal doesn't mention any of the ongoing work in that area, and it doesn't offer any other examples of where Result<> would be clearly superior enough that warrant it being placed on equal ground with Swift's native error handling. It would be extremely helpful to flesh that out more—if there *are* strong use cases for why the language should offer users the ability to declare two different forms of error-propagating APIs, the proposal would be helped by showing them.</div><div><br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div><br></div><div><br></div><div><br></div><div></div></div><div style="word-wrap:break-word;line-break:after-white-space"><div>Jon</div></div><div style="word-wrap:break-word;line-break:after-white-space"><div><br><div><span class="m_-2968819130997084382Apple-tab-span" style="white-space:pre-wrap">        </span><br><div><br><blockquote type="cite"><div>On Nov 2, 2017, at 3:30 PM, Tony Allevato <<a href="mailto:tony.allevato@gmail.com" target="_blank">tony.allevato@gmail.com</a>> wrote:</div><br class="m_-2968819130997084382Apple-interchange-newline"><div><div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Thu, Nov 2, 2017 at 12:21 PM Jon Shier <<a href="mailto:jon@jonshier.com" target="_blank">jon@jonshier.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><span class="m_-2968819130997084382m_2124999904820351422Apple-tab-span" style="white-space:pre-wrap">        </span>The Result type I’ve outlined includes the functions necessary to translate between do try catch and Result. But I fundamentally disagree with your characterization of Swift’s error handling. At most, Swift strives to hide the line between normal functions and error throwing ones, but only until the developer needs access to those errors. If you’re using an API that takes throwing functions and handles the do / catch for you, then sure, you’ll never see the result of those functions as anything more than the values you get from those APIs But anyone writing their own try / catch statements is quite clearly going to see the result/error separation that Result encapsulates. In quite a few cases, passing an encapsulation around rather than having to either mark all functions as throwing in order to propagate an error, or constantly implementing try / catch, results is code that is far easier to read, write, and reason about it.</div></blockquote><div><br></div><div>I would think the opposite is true.</div><div><br></div><div> let value = compute()</div><div><br></div><div>Looking at this line of code, I have no idea whether I should expect to handle errors or not. Does "compute" return a Result<> or just the value I want? If we used throwing instead, it's obvious without any other context that an error can occur there:</div><div><br></div><div> let value = try compute()</div><div><br></div><div>That's another explicit design choice in Swift, that "try" marks expressions so it's very clear which expressions can throw, rather than just being a block that surrounds an arbitrarily long amount of code. Result<> provides none of that context.</div><div><br></div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space">Of course it’s not an absolute solution, which is why the ability to turn a Result into a throwing function exists, but instead a complement to the current error handling in Swift.<div><br></div><div><br></div><div></div></div><div style="word-wrap:break-word;line-break:after-white-space"><div>Jon</div></div><div style="word-wrap:break-word;line-break:after-white-space"><div><br><div><br><blockquote type="cite"><div>On Nov 2, 2017, at 3:11 PM, Tony Allevato <<a href="mailto:tony.allevato@gmail.com" target="_blank">tony.allevato@gmail.com</a>> wrote:</div><br class="m_-2968819130997084382m_2124999904820351422Apple-interchange-newline"><div><div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Thu, Nov 2, 2017 at 11:58 AM Jon Shier <<a href="mailto:jon@jonshier.com" target="_blank">jon@jonshier.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><span class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552Apple-tab-span" style="white-space:pre-wrap">        </span>You would continue to be free to discourage the usage of Result for whatever you want. For the rest of us, Result isn’t intended to replace throws or do/catch, but provide a way to accomplish things in a much more compact and sometimes natural way. As with any API it could be used stupidly. But frankly, what developers what to do to wrap their errors is up to them.</div></blockquote><div><br></div><div>And it still is, with the Result implementations that are available to third-parties today.</div><div><br></div><div>My concerns regarding Result aren't about my personal discouragement of its use, but the *reasons* why I discourage its use. The Swift language very deliberately draws a line between result outcomes that are return values and error outcomes that are thrown, and it implements not only standard library types but also language syntactic sugar to support those.</div><div><br></div><div>If someone wants to depend on a third-party Result<> to conflate successful outcomes and error outcomes in their own code, that's absolutely their right. But entry into the standard library has a much higher bar, and what we're talking about here is adding a feature that now would give users two disparate and incompatible ways (without explicit transformations, or other syntactic sugar) of handling errors. That makes me uneasy from the point of view of both an API designer and consumer, and just restating that it's a common pattern and people want it doesn't address those concerns.</div><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space">Adding Result is just a way of blessing a result/error representation, since it has become a rather common pattern. If you’ve looked at the implementation I showed, you’ll see that there’s far more functionality than just a Result type, including API for converting back and forth from throwing functions, as well as functional transforms. Result is a complement to try do catch, not a replacement.<div><br></div><div><br></div><div><br></div><div></div></div><div style="word-wrap:break-word;line-break:after-white-space"><div>Jon</div></div><div style="word-wrap:break-word;line-break:after-white-space"><div><br><div><span class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552Apple-tab-span" style="white-space:pre-wrap">        </span><br><div><span class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552Apple-tab-span" style="white-space:pre-wrap">        </span><br><div><br><blockquote type="cite"><div>On Nov 2, 2017, at 2:48 PM, Tony Allevato <<a href="mailto:tony.allevato@gmail.com" target="_blank">tony.allevato@gmail.com</a>> wrote:</div><br class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552Apple-interchange-newline"><div><div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Thu, Nov 2, 2017 at 11:32 AM Jon Shier <<a href="mailto:jon@jonshier.com" target="_blank">jon@jonshier.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><span class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552m_7577137149950176343Apple-tab-span" style="white-space:pre-wrap">        </span>That’s been an argument against Result for 2 years now. The usefulness of the type, even outside of whatever asynchronous language support the core team comes up with, perhaps this year, perhaps next year, is still very high. Even as something that just wraps throwing functions, or otherwise exists as a local, synchronous value, it’s still very useful as way to encapsulate the value/error pattern.</div></blockquote><div><br></div><div>This is one of the parts that concerns me, actually. The beauty of Swift's error design is that function results denote expected/successful outcomes and thrown errors denote unexpected/erroneous outcomes. Since they are different, each is handled through its own language constructs, and since the language itself supports it (rather than being entirely type-based), you don't have the proliferation of unwrapping boilerplate that you have with Result<>.</div><div><br></div><div>In our own code bases, I actively discourage the use of Result<> in that way, because it tries to cram both of those concepts into the expected/successful outcomes slot in the language. For asynchronous APIs that's somewhat unavoidable today, but if that's going to change, I'd rather the language focus on a way that's consistent with other error handling already present in Swift.</div><div><br></div><div>Adding an API to the standard library is the core team saying "this is blessed as something around which we support APIs being designed." IMO, I'd prefer it if the language did *not* bless two disparate ways of communicating error outcomes but rather converged on one.</div><div><br></div><div>IMO, "things aren't happening fast enough" isn't great motivation for putting something permanently into the standard library or the language without considering the context of other things going on around it. If you're going to propose something that overlaps with asynchronous APIs, it only helps your case if you can discuss how it can integrate—rather than collide—with those efforts.</div><div><br></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space">That pattern will likely never go away. Additionally, having the Result type in the standard library removes a source of conflict between all other Result implementations, which are becoming more common.</div><div style="word-wrap:break-word;line-break:after-white-space"><br><div><br><blockquote type="cite"><div>On Nov 2, 2017, at 2:26 PM, Tony Allevato <<a href="mailto:tony.allevato@gmail.com" target="_blank">tony.allevato@gmail.com</a>> wrote:</div><br class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552m_7577137149950176343Apple-interchange-newline"><div><div dir="ltr">Given that the Swift team is currently working on laying the groundwork for asynchronous APIs using an async/await model, which would presumably tie the throwing cases more naturally into the language than what is possible using completion-closures today, are we sure that this wouldn't duplicate any efforts there or be made obsolete through other means?<div><br></div><div>In other words, while Result<> can be a very useful foundational component on its own, I think any proposal for it can't be made in isolation, but very much needs to consider other asynchronous work going on in the language.</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr">On Thu, Nov 2, 2017 at 11:15 AM Jon Shier via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space">You don’t lose it, it’s just behind `Error`. You can cast out whatever strong error type you need without having to bind an entire type to it generically. If getting a common error type out happens a lot, I usually add a convenience property to `Error` to do the cast for me. Plus, having to expose an entire new error wrapper is just a non starter for me and doesn’t seem necessary, given how Result is currently used in the community.<div><br></div><div><br></div><div></div></div><div style="word-wrap:break-word;line-break:after-white-space"><div>Jon</div></div><div style="word-wrap:break-word;line-break:after-white-space"><div><br><div><br><blockquote type="cite"><div>On Nov 2, 2017, at 2:12 PM, Dave DeLong <<a href="mailto:swift@davedelong.com" target="_blank">swift@davedelong.com</a>> wrote:</div><br class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552m_7577137149950176343m_-350027757980587147Apple-interchange-newline"><div><div style="word-wrap:break-word;line-break:after-white-space"><div>I think I’d personally rather see this done with a generic error as well, like:</div><div><br></div><div>enum GenericResult<T, E: Error> {</div><div><span class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552m_7577137149950176343m_-350027757980587147Apple-tab-span" style="white-space:pre-wrap">        </span>case success(T)</div><div><span class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552m_7577137149950176343m_-350027757980587147Apple-tab-span" style="white-space:pre-wrap">        </span>case failure(E)</div><div>}</div><div><br></div>And a typealias:<div><br></div><div>typealias Result<T> = GenericResult<T, AnyError></div><div><br></div><div>This would require an “AnyError” type to type-erase a specific Error, but I’ve come across many situations where a strongly-typed error is <i>incredibly </i>useful, and I’d be reluctant to see that thrown away.</div><div><br></div><div>Dave<br><div><br><blockquote type="cite"><div>On Nov 2, 2017, at 12:08 PM, Jon Shier via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>> wrote:</div><br class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552m_7577137149950176343m_-350027757980587147Apple-interchange-newline"><div><div style="word-wrap:break-word;line-break:after-white-space">Swift-Evolution:<div><span class="m_-2968819130997084382m_2124999904820351422m_6250568808190541552m_7577137149950176343m_-350027757980587147Apple-tab-span" style="white-space:pre-wrap">        </span>I’ve written a first draft of a proposal to add Result<T> to the standard library by directly porting the Result<T> type used in Alamofire to the standard library. I’d be happy to implement it (type and tests for free!) if someone could point me to the right place to do so. I’m not including it directly in this email, since it includes the full implementation and is therefore quite long. (Discourse, please!) </div><div><br></div><div><a href="https://github.com/jshier/swift-evolution/blob/master/proposals/0187-add-result-to-the-standard-library.md" target="_blank">https://github.com/jshier/swift-evolution/blob/master/proposals/0187-add-result-to-the-standard-library.md</a></div><div><br></div><div><br></div><div>Thanks, </div><div><br></div><div>Jon Shier</div><div><br></div><div><br></div></div>_______________________________________________<br>swift-evolution mailing list<br><a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></div></blockquote></div><br></div></div></div></blockquote></div><br></div></div>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div>
</div></blockquote></div><br></div></blockquote></div></div>
</div></blockquote></div><br></div></div></div></div></blockquote></div></div>
</div></blockquote></div><br></div></div></blockquote></div></div>
</div></blockquote></div><br></div></div></div></blockquote></div></div>