[swift-evolution] Adding Result to the Standard Library

Jon Shier jon at jonshier.com
Sun Nov 5 22:13:40 CST 2017


All:
	I’ve updated the proposal to include a better introduction and examples of Result usage to better justify its inclusion in the standard library.

Re: Result<T, E> & typed throws
	This seems to be the most contentious part of this proposal. As explained in the proposal, Result<T> allows painless usage with all current Swift APIs, especially Apple’s. At worst, this version of Result requires casting the Error value to a concrete type if you need to do something with that error. I believe that tradeoff is worthwhile, since it guarantees painless integration with APIs that return multiple error types, return undocumented error types, reserve the right to change error types, or otherwise just return Error. While Result<T, E> could work here, I usually see it done by casting an unknown error to NSError, which, to me, is an anti pattern. A possible solution here is the introduction of an AnyError type that could be used to wrap any unknown errors in a concrete type. Such a type presents usability concerns, as using it automatically would be difficult, requiring users to manually wrap unknown errors.
	This consideration is further complicated by the possible addition of typed throws in the future. However, the most commonly suggested implementation fo typed throws keeps the ability for throws to be untyped. Additionally, the feature usually allows multiple types to be thrown from a single function. Result<T> can handle all of these scenarios automatically, since it reduces all errors down to Error. A Result<T, E> however, would either lose the ability to encapsulate any function with multiple error types, or otherwise have to wrap those cases in something like AnyError, in additional to having to do so in the untyped case. It seems likely to me that this would become the more common case, losing most of the elegance of Result<T, E> in exchange for those rare scenarios where a single typed error is known. However, I would like input from the core team here.
	Finally, part of any Swift Result type should be the ability to turn a Result back into a throwing function. Addition of an AnyError wrapper would greatly complicate this usage of a Result<T, E> type, as the user would have to attempt a cast to AnyError, then cast the contained error to a concrete type. Given what would probably be frequent usage of AnyError, this is a rather glaring ergonomic issue.

Re: Result and future async/await
	While I’m not intimately familiar with the whole of the current async proposal, I believe it’s possible it can be rectified with Result. Similar to how Result acts as a manually propagated error solution, it could do the same to the propagation of async results and errors. Result could capture the result of said executions, especially if the keywords could be applied to initializers: await Result { async String(url:…) }. This would have many of the same use cases I’ve outlined in the proposal in regards to throwing functions. Additionally, unless the plan is to automatically convert all current async APIs in Swift or Apple’s frameworks to the async / await model, Result would still have a place in handling older style APIs using completion handlers and such.

Re: Deeper integration with the Standard Library
	This proposal includes the most common functionality included with Result implementations available to the community. Given the lack of deeper integration attempted, I’m not sure how far such integration should or needs to go. But I’ll respond to some commonly suggested ones and offer some of my own here.
	• Convenience Operators: To be honest, I’m not sure this is necessary. None of the Result libraries I’ve seen have implemented such a thing and I’m not sure why it would be necessary. The proposed Result type already includes the ability to wrap a throwing closure and to unwrap a Result using try. So I guess a better outline of what, exactly, would be more convenient about such an operator would be appreciated. Perhaps some variant of the ternary operator? But this is all about hiding the enum nature of Result, like Optional does, right? 
	• Reconcile () -> Result<T> and () throws -> T: To be honest, I’m not even sure where to start here. Personally I’d think something like this would be separate from the introduction of Result, given the fundamental change to language syntax this would represent. Would this equivalence be similar to any other feature in Swift? I can’t think of any.
	One convenience feature I have used are APIs on Collection to deal with collections of Results. This is useful when needing to operate on all of the values or errors. Another bit I really didn’t touch on, but which could be hugely useful, is the automatic conversion of completion handlers in imported Objective-C APIs to use Result. This would a huge, and somewhat dangerous undertaking, but something which greatly improve those APIs.
	My biggest concern here is that expanding the proposal beyond just introducing the type and perhaps some top level convenience APIs, like the Collection API mentioned, greatly increases the language impact and implementation effort. I’d like to keep the proposal to just what’s necessary to introduce the type and add language or convenience features around it in the future as targeted proposals, rather than one giant one that encompasses everything all at once.



Jon


> On Nov 5, 2017, at 6:40 AM, Rod Brown <rodney.brown6 at icloud.com> wrote:
> 
> I was thinking the same thing. Typed throws vs `Error` throws are the two major differences between different Result implementations, and they seem somewhat tied from a discussion perspective.
> 
> I agree with others here, I would like to see this added to the library, and I think it’s a generally valuable type that has broad uses beyond the completion handler solution that it’s commonly been used for. But if we add things to do the standard library, they need to be consistent, with the direction of Swift, and that’s a big call at this stage to either write in or out typed throws...
> 
> Rod
> 
> On 3 Nov 2017, at 2:41 pm, Chris Lattner via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
> 
>> 
>>> On Nov 2, 2017, at 11:08 AM, Jon Shier via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> Swift-Evolution:
>>> 	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!) 
>>> 
>>> https://github.com/jshier/swift-evolution/blob/master/proposals/0187-add-result-to-the-standard-library.md <https://github.com/jshier/swift-evolution/blob/master/proposals/0187-add-result-to-the-standard-library.md>
>> I’m generally supportive of this, but the design of such a thing forces another contentious issue: whether the error handling model should be extended to support "typed throws”.  Without result, we can carry on pushing the "typed throws” debate down the road.  Adding it would force that issue to be decided, which is complicated.
>> 
>> -Chris
>> 
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20171105/f18e57ac/attachment.html>


More information about the swift-evolution mailing list