[swift-evolution] Adding Result to the Standard Library

Tony Allevato tony.allevato at gmail.com
Thu Nov 2 14:30:38 CDT 2017


On Thu, Nov 2, 2017 at 12:21 PM Jon Shier <jon at jonshier.com> wrote:

> 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.
>

I would think the opposite is true.

    let value = compute()

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:

    let value = try compute()

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.



> 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.
>
>
> Jon
>
>
> On Nov 2, 2017, at 3:11 PM, Tony Allevato <tony.allevato at gmail.com> wrote:
>
>
>
> On Thu, Nov 2, 2017 at 11:58 AM Jon Shier <jon at jonshier.com> wrote:
>
>> 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.
>>
>
> And it still is, with the Result implementations that are available to
> third-parties today.
>
> 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.
>
> 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.
>
>
>
>
>> 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.
>>
>>
>>
>> Jon
>>
>>
>>
>>
>> On Nov 2, 2017, at 2:48 PM, Tony Allevato <tony.allevato at gmail.com>
>> wrote:
>>
>>
>>
>> On Thu, Nov 2, 2017 at 11:32 AM Jon Shier <jon at jonshier.com> wrote:
>>
>>> 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.
>>>
>>
>> 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<>.
>>
>> 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.
>>
>> 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.
>>
>> 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.
>>
>>
>>
>>
>>> 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.
>>>
>>>
>>> On Nov 2, 2017, at 2:26 PM, Tony Allevato <tony.allevato at gmail.com>
>>> wrote:
>>>
>>> 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?
>>>
>>> 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.
>>>
>>>
>>> On Thu, Nov 2, 2017 at 11:15 AM Jon Shier via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>>> 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.
>>>>
>>>>
>>>> Jon
>>>>
>>>>
>>>> On Nov 2, 2017, at 2:12 PM, Dave DeLong <swift at davedelong.com> wrote:
>>>>
>>>> I think I’d personally rather see this done with a generic error as
>>>> well, like:
>>>>
>>>> enum GenericResult<T, E: Error> {
>>>> case success(T)
>>>> case failure(E)
>>>> }
>>>>
>>>> And a typealias:
>>>>
>>>> typealias Result<T> = GenericResult<T, AnyError>
>>>>
>>>> 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 *incredibly
>>>> *useful, and I’d be reluctant to see that thrown away.
>>>>
>>>> Dave
>>>>
>>>> On Nov 2, 2017, at 12:08 PM, Jon Shier via swift-evolution <
>>>> 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
>>>>
>>>>
>>>> Thanks,
>>>>
>>>> Jon Shier
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20171102/071b964f/attachment.html>


More information about the swift-evolution mailing list