Adding Result to the Standard Library

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

3 Likes

With the upcoming async-await constructs supporting do-try-catch natively, what would the use-case for an explicit Result type be?

Dan

···

On Nov 2, 2017, at 11:08 AM, Jon Shier via swift-evolution <swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

1 Like

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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

3 Likes

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@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I have been writing code in a style that uses explicit effect handling lately. In this style of code, a request describing an async task is returned from a function and later interpreted by a library. When the task completes the library passes the result to completion handler that is part of the task description (which produces subsequent effects to interpret).

It isn’t possible to express the completion handlers attached to task descriptions as an async call. The function needs to return the task description immediately. For this reason, I believe it will be necessary to continue using a Result type in code written in this style even after async / await is introduced.

···

On Nov 2, 2017, at 1:53 PM, Dan Stenmark via swift-evolution <swift-evolution@swift.org> wrote:

With the upcoming async-await constructs supporting do-try-catch natively, what would the use-case for an explicit Result type be?

Dan

On Nov 2, 2017, at 11:08 AM, Jon Shier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

This is largely unanswerable until that feature is actually designed. However, I can imaging wrapping an async-await in a Result to be easily passed around or transformed. Plus all of the usual non-asynchronous uses of Result in the first place.

Jon

···

On Nov 2, 2017, at 2:52 PM, Dan Stenmark <daniel.j.stenmark@gmail.com> wrote:

With the upcoming async-await constructs supporting do-try-catch natively, what would the use-case for an explicit Result type be?

Dan

On Nov 2, 2017, at 11:08 AM, Jon Shier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

This is clearly a fine addition to the standard library; even Swift's Error
Handling Rationale (
https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst)
mentions such an addition

What separates standard library types from other types is that they have
language level support, and the wrapping and unwrapping syntax here could
definitely benefit from it (`.unwrap()`--which should be `.unwrapped()`
incidentally--is so much less elegant in comparison to `?` and `!` for
optionals (not that `Result` should use the exact such syntax for a
distinct operation)). It would be a shame to transpose a third-party
`Result` to the standard library without considering if any such tweaks
would substantially improve ergonomics, interconversion with Optional and
throws, etc.

···

On Thu, Nov 2, 2017 at 1:08 PM, Jon Shier via swift-evolution < swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

···

On Nov 2, 2017, at 11:08 AM, Jon Shier via swift-evolution <swift-evolution@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

I’m late to this particular party, but having just caught up with the thread I’m surprised that no one substantially addressed the stylistic duality that a `public enum Result` would bring.

In short, I’d rather Result be a struct than an enum.

I too implemented a Result, for obvious reasons. I was, however, unsatisfied that it added another interface for error handling, namely switching over the enum — it’s not really better, not really worse, but now there are more error handling patterns to look for in your code.

My solution was to simply switch to a `struct Result`, where the enum is private. The only way to get the value out is via a throwing method. See <https://gist.github.com/glessard/48f4c1305ac20b1b99c1bbdc2fb6290c> for a no-frills implementation.

This has all the advantages of the Result enum — it’s easily used in asynchronous situations and can implement the desired functional/monadic niceties, but without exposing an unnecessary alternate interface to Swift’s native error handling.

Cheers,
Guillaume Lessard

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@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I’m certainly willing to adjust API to better match convention and guidelines. However, part of the proposal’s basis is the popularity of the Alamofire implementation (which is rather similar to the antitypical one in regards to additional API offered). Adding special syntax for it isn’t really something I want to do, as ever bit of that needs additional justification beyond the fact that’s it’s already in use.

Jon

···

On Nov 2, 2017, at 8:01 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

This is clearly a fine addition to the standard library; even Swift's Error Handling Rationale (https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst) mentions such an addition

What separates standard library types from other types is that they have language level support, and the wrapping and unwrapping syntax here could definitely benefit from it (`.unwrap()`--which should be `.unwrapped()` incidentally--is so much less elegant in comparison to `?` and `!` for optionals (not that `Result` should use the exact such syntax for a distinct operation)). It would be a shame to transpose a third-party `Result` to the standard library without considering if any such tweaks would substantially improve ergonomics, interconversion with Optional and throws, etc.

On Thu, Nov 2, 2017 at 1:08 PM, Jon Shier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Proposing syntactic sugar for this at the same time would go a long way
toward making me less reluctant to support it. As a type by itself, I don’t
think it holds its weight in the standard library.

The question that I’d want to see answered is, is it possible to make it so
that these two functions are identical for all intents and purposes?

func foo() throws -> Int
func foo() -> Result<Int>

Doing that at the call site is easy enough (the proposed implementation
does much of that, but more could be done at the language level to remove
the manual unwrapping), but I’m not sure how you reconcile the fact that,
of those two declarations, an author *does* have to pick one to write.

One thing I can think of off the top of my head is forbid functions from
returning Result<> but allow them to be created by assignment from a
throwing function. That, however, seems like an arbitrary and just flat out
bizarre limitation and I can’t really bring myself to support it.

I guess the problem I want to avoid is that, even if you sugar away all the
differences between Result<> and throwing when it comes to *calling* these
functions, there would still be two ways to declare essentially the same
function, and the choice of which someone uses becomes arbitrary and
meaningless.

···

On Thu, Nov 2, 2017 at 5:02 PM Xiaodi Wu via swift-evolution < swift-evolution@swift.org> wrote:

This is clearly a fine addition to the standard library; even Swift's
Error Handling Rationale (
https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst)
mentions such an addition

What separates standard library types from other types is that they have
language level support, and the wrapping and unwrapping syntax here could
definitely benefit from it (`.unwrap()`--which should be `.unwrapped()`
incidentally--is so much less elegant in comparison to `?` and `!` for
optionals (not that `Result` should use the exact such syntax for a
distinct operation)). It would be a shame to transpose a third-party
`Result` to the standard library without considering if any such tweaks
would substantially improve ergonomics, interconversion with Optional and
throws, etc.

On Thu, Nov 2, 2017 at 1:08 PM, Jon Shier via swift-evolution < > swift-evolution@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I'm also in favor of providing the ability to specify the type of the error
for the result. It provides self-documenting and type safety advantages
over the generic Error that really makes the type much more useful.

The ideal would be to have the two possible syntax (Result<T> and
Result<T,E>) , but i'm not sure how feasible that is.

···

On Thu, Nov 2, 2017 at 7:15 PM, Jon Shier via swift-evolution < swift-evolution@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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

To be fair, I would want to see the outcome of the `typed throws` discussion first before moving the discussion about `Result` forward.

···

Am 3. November 2017 um 04:41:32, Chris Lattner via swift-evolution (swift-evolution@swift.org) schrieb:

On Nov 2, 2017, at 11:08 AM, Jon Shier via swift-evolution <swift-evolution@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

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

1 Like

Right, to me there is not a lot of value in adding Result as it exists in
AlamoFire. We will (eventually) use the Swift Package Manager for things
like this. The value would be in integrating it like Optionals. e.g. (using
a strawman symbol)

    var x: Int‽ = 5
    var y: Int‽ = anErrorValue

    func foo() -> Int‽ { ... }

    if let x = foo() {
        // x is Int
    } else {
        // somehow access the error
    }

    guard let x = foo() else {
        // Again somehow access the error
    }

    func bar() throws -> String { ... }
    let x = try‽ bar() // x is String‽
    let y = x! // y is String

    // Possibly even make it throw? (just using a random symbol again)
    let z = try x¡

···

On Fri, Nov 3, 2017 at 2:02 AM, Xiaodi Wu via swift-evolution < swift-evolution@swift.org> wrote:

This is clearly a fine addition to the standard library; even Swift's
Error Handling Rationale (https://github.com/apple/swift/blob/master/docs/
ErrorHandlingRationale.rst) mentions such an addition

What separates standard library types from other types is that they have
language level support, and the wrapping and unwrapping syntax here could
definitely benefit from it (`.unwrap()`--which should be `.unwrapped()`
incidentally--is so much less elegant in comparison to `?` and `!` for
optionals (not that `Result` should use the exact such syntax for a
distinct operation)). It would be a shame to transpose a third-party
`Result` to the standard library without considering if any such tweaks
would substantially improve ergonomics, interconversion with Optional and
throws, etc.

On Thu, Nov 2, 2017 at 1:08 PM, Jon Shier via swift-evolution < > swift-evolution@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/propos
als/0187-add-result-to-the-standard-library.md

Thanks,

Jon Shier

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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@swift.org> wrote:

On Nov 2, 2017, at 11:08 AM, Jon Shier via swift-evolution <swift-evolution@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

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

You mention `.unwrap()`. This might be a good time to mention a previous discussion of an `Unwrappable` protocol that provides biased unwrapping and can extend unwrapping syntax to non-Optional types:

https://gist.github.com/erica/aea6a1c55e9e92f843f92e2b16879b0f

-- E

···

On Nov 2, 2017, at 6:02 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

This is clearly a fine addition to the standard library; even Swift's Error Handling Rationale (https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst) mentions such an addition

What separates standard library types from other types is that they have language level support, and the wrapping and unwrapping syntax here could definitely benefit from it (`.unwrap()`--which should be `.unwrapped()` incidentally--is so much less elegant in comparison to `?` and `!` for optionals (not that `Result` should use the exact such syntax for a distinct operation)). It would be a shame to transpose a third-party `Result` to the standard library without considering if any such tweaks would substantially improve ergonomics, interconversion with Optional and throws, etc.

On Thu, Nov 2, 2017 at 1:08 PM, Jon Shier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

3 Likes

For some generic function

func doSomething() -> Result<String>

You could write (potentially pseudocode);

func doSomething() throws -> String {
   return try doSomething().value()
}

with Result defined as:

enum Result<T> {
case success(T)
case error(Error)
func value() throws -> T {
     switch self {
        case success(let t):
            return t
        case error(let e):
            throw e
      }
  }
}

IMHO, the real value for a Result type (or Future/Promise type) in the core library would be the compiler support for the type. Why would you want to define two versions of the doSomething function just to deal with code that wants a Result and code which doesn't?

That, and people implementing Result themselves internally in 15 lines making it a question of supporting *everyone’s* Result types, not just a system type.

-DW

···

On Nov 14, 2017, at 4:40 PM, Guillaume Lessard via swift-evolution <swift-evolution@swift.org> wrote:

I’m late to this particular party, but having just caught up with the thread I’m surprised that no one substantially addressed the stylistic duality that a `public enum Result` would bring.

In short, I’d rather Result be a struct than an enum.

I too implemented a Result, for obvious reasons. I was, however, unsatisfied that it added another interface for error handling, namely switching over the enum — it’s not really better, not really worse, but now there are more error handling patterns to look for in your code.

My solution was to simply switch to a `struct Result`, where the enum is private. The only way to get the value out is via a throwing method. See <https://gist.github.com/glessard/48f4c1305ac20b1b99c1bbdc2fb6290c> for a no-frills implementation.

This has all the advantages of the Result enum — it’s easily used in asynchronous situations and can implement the desired functional/monadic niceties, but without exposing an unnecessary alternate interface to Swift’s native error handling.

Cheers,
Guillaume Lessard

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

You can support all styles with enum as well. What don’t you do this:

public enum Result<T> {
    
    case value(T)
    case error(Error)
    
    public init(_ value: T) { self = .value(value) }
    public init(error: Error) { self = .error(error) }

    public func get() throws -> T {
        switch self {
        case let .value(value): return value
        case let .error(error): throw error }
    }
    
    public func map<U>(_ transform: (T) throws -> U) throws -> U { return try transform(get()) }
    
    public var value: T? {
        switch self {
        case let .value(value): return value
        case .error: return nil }
    }
    
    public var error: Error? {
        switch self {
        case .value: return nil
        case let .error(error): return error }
    }
}

···

On Nov 14, 2017, at 3:40 PM, Guillaume Lessard via swift-evolution <swift-evolution@swift.org> wrote:

I’m late to this particular party, but having just caught up with the thread I’m surprised that no one substantially addressed the stylistic duality that a `public enum Result` would bring.

In short, I’d rather Result be a struct than an enum.

I too implemented a Result, for obvious reasons. I was, however, unsatisfied that it added another interface for error handling, namely switching over the enum — it’s not really better, not really worse, but now there are more error handling patterns to look for in your code.

My solution was to simply switch to a `struct Result`, where the enum is private. The only way to get the value out is via a throwing method. See <https://gist.github.com/glessard/48f4c1305ac20b1b99c1bbdc2fb6290c> for a no-frills implementation.

This has all the advantages of the Result enum — it’s easily used in asynchronous situations and can implement the desired functional/monadic niceties, but without exposing an unnecessary alternate interface to Swift’s native error handling.

Cheers,
Guillaume Lessard

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

👆 👏

There’s a lot of stuff I’m tired of implementing myself while waiting for the the core team “to lay the ground for”. Result is up there near the top of my list too.

Dave

···

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

On Nov 2, 2017, at 2:26 PM, Tony Allevato <tony.allevato@gmail.com <mailto:tony.allevato@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@swift.org <mailto:swift-evolution@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@davedelong.com <mailto:swift@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution