Adding Result to the Standard Library


(Nick Keets) #15

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


(Rod Brown) #16

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


(Erica Sadun) #17

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


(David Waite) #18

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


(Hooman Mehr) #19

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


(Dave DeLong) #20

  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


(Jon Shier) #21

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.

···

On Nov 2, 2017, at 2:26 PM, Tony Allevato <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


(TJ Usiyan) #22

+1 from me… for what it's worth. The value, in my opinion, is that we won't
each have to add result. I would prefer Either<A,B> but I will take
Result<A>.

···

On Thu, Nov 2, 2017 at 2:35 PM, Dave DeLong via swift-evolution < swift-evolution@swift.org> wrote:

On Nov 2, 2017, at 12:32 PM, Jon Shier <jon@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. 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.

:point_up_2: :clap:

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 2:26 PM, Tony Allevato <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> 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

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


(Dave DeLong) #23

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>

I mentioned this equivalency during the async/await debate: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170821/039196.html

I think this would be a great addition.

Dave

···

On Nov 2, 2017, at 6:11 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

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 <mailto: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 <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


(Dave DeLong) #24

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>

I mentioned this equivalency during the async/await debate: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170821/039196.html

I think this would be a great addition.

Additionally, Erica had some thoughts around how to make unwrapping even easier, which includes support for Result<T>:

Dave

···

On Nov 2, 2017, at 6:19 PM, Dave DeLong <swift@davedelong.com> wrote:

On Nov 2, 2017, at 6:11 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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 <mailto: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 <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


(Tony Allevato) #25

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.

···

On Thu, Nov 2, 2017 at 11:32 AM Jon Shier <jon@jonshier.com> wrote:

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


(Xiaodi Wu) #26

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.

Agree, issues such as this *must* be addressed for a successful `Result`
proposal. The resulting design should be highly coherent and reflect a
unitary vision of error handling; it cannot be merely a bolting-on of an
external Result type.

···

On Thu, Nov 2, 2017 at 7:11 PM, Tony Allevato <tony.allevato@gmail.com> wrote:

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


(Xiaodi Wu) #27

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.

On the contrary, every addition to the standard library must justify why it
must be in *the standard library*, as opposed to another core library or a
third-party library. Consider this standard articulated in the Foundation
README:

How do we decide if something belongs in the standard library or

Foundation?

In general, the dividing line should be drawn in overlapping area of what

people consider the language and what people consider to be a library
feature. For example, Optional is a type provided by the standard library.
However, the compiler understands the concept to provide support for things
like optional-chaining syntax. The compiler also has syntax for creating
Arrays and Dictionaries. On the other hand, the compiler has no built-in
support for types like URL. URL also ties into more complex functionality
like basic networking support. Therefore this type is more appropriate for
Foundation.

I would argue that a successful addition to the standard library *must*
have such additional justification about why it needs built-in support. If
it's already in use as a third-party library, and you're arguing that the
third-party design is already quite satisfactory and there's no built-in
support required, then that's fundamentally an argument that it *doesn't*
need to be in the standard library.

···

On Thu, Nov 2, 2017 at 7:04 PM, Jon Shier <jon@jonshier.com> wrote:

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


(Benjamin.G) #28

Just an idea for the type declaration :

Why not use the same ? as Optional, but with the type of the error behind :

Such as

var x: Int?Error

Optional Int (Int?) would be seen a special case of Result where the error
type is nil.

The advantage of this syntax is that it would let us specify the type of
the error if we want it.

···

On Fri, Nov 3, 2017 at 11:45 AM, Nick Keets via swift-evolution < swift-evolution@swift.org> wrote:

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/swif
t/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

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


(Benjamin.G) #29

Actually i'd even prefer :
var x: Int ?? Error

the spaces makes it more readable, it looks like what you'd do with the ??
operator already, and it seems coherent with the syntax for protocol
composition.

···

On Fri, Nov 3, 2017 at 12:12 PM, Benjamin G <benjamin.garrigues@gmail.com> wrote:

Just an idea for the type declaration :

Why not use the same ? as Optional, but with the type of the error behind :

Such as

var x: Int?Error

Optional Int (Int?) would be seen a special case of Result where the error
type is nil.

The advantage of this syntax is that it would let us specify the type of
the error if we want it.

On Fri, Nov 3, 2017 at 11:45 AM, Nick Keets via swift-evolution < > swift-evolution@swift.org> wrote:

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/swif
t/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

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


(Wallacy) #30

If my memory does not fail, there has also been a discussion about adding a
"payload" to the optional types that fit into that context.

Something like:

//Current
enum Optional<T>{
case Some(T)
case None
}

// Adding
enum Optional<T,Error>{
case Some(T)
case None(Error)
//Maybe adding support functions too
}

And some compiler magics to make Optional<T,Error> always to be convertible
to Optional<T> (losing Error info of course)... And support to optional
chaining and other current optional tricks.

In this case:

let some = try? foo() // some is Optional<T,Error>

some?.bar() // works

And we can do:

switch some{
   case .Some(let value):
   // ...
  case .None(let error):
  //
}

Other idea was presented in Swift 2/3 time frame was just:

enum Optional<T>{
case Some(T)
case None
var payload:Any!
}

I am not saying that this is the best way, but in fact it is better to
think about what we can do to improve the current scenario, than to
introduce another type that may or may not make everything more confusing.

···

Em sex, 3 de nov de 2017 às 09:13, Benjamin G via swift-evolution < swift-evolution@swift.org> escreveu:

Just an idea for the type declaration :

Why not use the same ? as Optional, but with the type of the error behind :

Such as

var x: Int?Error

Optional Int (Int?) would be seen a special case of Result where the error
type is nil.

The advantage of this syntax is that it would let us specify the type of
the error if we want it.

On Fri, Nov 3, 2017 at 11:45 AM, Nick Keets via swift-evolution < > swift-evolution@swift.org> wrote:

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

_______________________________________________
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


(Jon Shier) #31

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

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

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


(Hooman Mehr) #32

Oops, forgot to put the initializers that are the most useful:

    public init(_ expression: @autoclosure () throws -> T) {
        do { self = .value(try expression() ) }
        catch { self = .error(error) }
    }
    
    public init(_ closure: () throws -> T) {
        do { self = .value(try closure()) }
        catch { self = .error(error) }
    }

···

On Nov 14, 2017, at 6:57 PM, Hooman Mehr via swift-evolution <swift-evolution@swift.org> wrote:

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 <mailto: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 <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


(Guillaume Lessard) #33

My point is precisely that perhaps we should not.

While the switch-over-result style is neither better nor worse than the try-catch style, having both in one body of code isn’t pleasant.

We can privilege the try-catch style and still get the benefits of Result.

Guillaume Lessard

···

On Nov 14, 2017, at 19:57, Hooman Mehr <hooman@mac.com> wrote:

You can support all styles with enum as well.


(Jon Shier) #34

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. 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@gmail.com> wrote:

On Thu, Nov 2, 2017 at 11:32 AM Jon Shier <jon@jonshier.com <mailto:jon@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@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