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 <[email protected]> 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
> <[email protected] <mailto:[email protected]>> wrote:
>
>>
>>> On Nov 2, 2017, at 11:08 AM, Jon Shier via swift-evolution
>>> <[email protected] <mailto:[email protected]>> 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
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution