Adding Result to the Standard Library

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

+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!)

GitHub - jshier/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.
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

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: [swift-evolution] Two thoughts on concurrency

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

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: [swift-evolution] Two thoughts on concurrency

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

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

2 Likes

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 (Apple · GitHub
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!)

GitHub - jshier/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Language.
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.

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

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

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

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

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

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&gt; 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

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.

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

Key words: “if that is going to change” and I would add “even if it changes would all async use cases map to the new paradigm?”. I understand your concerns, but I am also wary of promised silver bullet solutions that promise or aim to take care of all use cases...

···

Sent from my iPhone

On 2 Nov 2017, at 18:48, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

On Thu, Nov 2, 2017 at 11:32 AM 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.

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

You would continue to be free to discourage the usage of Result for
whatever you want. For the rest of us, Result isn’t intended to replace
throws or do/catch, but provide a way to accomplish things in a much more
compact and sometimes natural way. As with any API it could be used
stupidly. But frankly, what developers what to do to wrap their errors is
up to them.

And it still is, with the Result implementations that are available to
third-parties today.

My concerns regarding Result aren't about my personal discouragement of its
use, but the *reasons* why I discourage its use. The Swift language very
deliberately draws a line between result outcomes that are return values
and error outcomes that are thrown, and it implements not only standard
library types but also language syntactic sugar to support those.

If someone wants to depend on a third-party Result<> to conflate successful
outcomes and error outcomes in their own code, that's absolutely their
right. But entry into the standard library has a much higher bar, and what
we're talking about here is adding a feature that now would give users two
disparate and incompatible ways (without explicit transformations, or other
syntactic sugar) of handling errors. That makes me uneasy from the point of
view of both an API designer and consumer, and just restating that it's a
common pattern and people want it doesn't address those concerns.

···

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

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

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.

  What? That doesn’t make any sense at all. I’ve written this proposal to get a very popular and useful type into the standard library exactly because it’s so popular and useful. It’s so popular and useful, in fact, that users are running into issues getting all of the third-party implementations to play well together. I’ll be adding more to the proposal about the general usefulness of the Result type tomorrow, but it has often been said on this mailing list that one of the ways a type can become part of the standard library is by becoming popular in the community. My assertion is that Result has reached that point and so needs consideration for the benefit of not only all current users of the type, but the community in general.
  I could also be confused about what you mean about “built-in” support, or the types of things you’d think a standard library Result type should do that isn’t in the proposal. In that case, could you be much more specific about what additions you think it needs?

Jon

I'd say that this syntax would be even more coherent with protocol composition, given that x is effectively an Int or an Error:

var x: Int | Error

But aside from the specific syntax, I'm pretty sure it isn't the first time this request comes up and there were good reasons for rejecting it.

Elia Cereda

···

Il giorno 03 nov 2017, alle ore 13:10, Benjamin G via swift-evolution <swift-evolution@swift.org> ha scritto:

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

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

As I mentioned up-thread, this proposal isn’t going to go anywhere without a proper discussion of typed throws. There are good reasons for two possible designs:

1. Never add typed throws.
2. Add the ability to specify a single type thrown (typically an enum, but could be a struct), which defaults to Error if unspecified.

I don’t see any reason to add an arbitrary *list* of thrown types. Swift already has ways to specify alternatives (enums) and this would encourage exactly the behavior from APIs that we want to avoid.

This choice between 1/2 needs to be decided before introducing result, because #1 means it should be Result<T>, and #2 means it should be Result<T,E>. If this is important to you, I’d suggest starting a dedicated discussion thread about the topic.

-Chris

···

On Nov 6, 2017, at 4:13 AM, Jon Shier <jon@jonshier.com> wrote:

  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.

1 Like

As I mentioned up-thread, this proposal isn’t going to go anywhere without a proper discussion of typed throws. There are two possible designs that have strong rationale:

1. Never add typed throws.
2. Add the ability to specify a single type thrown (typically an enum, but could be a struct), which defaults to Error if unspecified.

In contrast, I don’t see any reason to add an arbitrary *list* of thrown types, and I can’t imagine such a design happening. Swift already has ways to specify alternatives (enums) and this would encourage exactly the behavior from APIs that we want to avoid.

This choice between 1/2 needs to be decided before introducing result, because #1 means it should be Result<T>, and #2 means it should be Result<T,E>. If this is important to you, I’d suggest starting a dedicated discussion thread about the topic.

-Chris

···

On Nov 6, 2017, at 4:13 AM, Jon Shier <jon@jonshier.com <mailto:jon@jonshier.com>> wrote:

  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.