[swift-evolution] Proposal: An Either Type in the STL
rjmccall at apple.com
Wed Dec 9 21:15:02 CST 2015
> On Dec 9, 2015, at 6:43 PM, Matthew Johnson <matthew at anandabits.com> wrote:
>> We considered it, had some specifics worked out, and then decided to put it on hold. Part of our reasoning was that it seemed more like an implementation detail of the async / CPS-conversion features we’d like to provide than an independently valuable feature, given that we don’t want to encourage people to write library interfaces using functional-style error handling instead of throws.
>> It’s also a feature that’s directly affected by the design of typed throws, which in turn poses some usability challenges for it. For example, without typed throws you really just want the type to be Result<T>. With typed throws, can you still write that, or do you have to write Result<T, ErrorType>? Also, if we want every function result signature to have a corresponding Result<> type, does that permanently prevent us to supporting multiple error types with “typed throws”? Also, would it be too frustrating to work with typed Result values if we don’t allow implicit covariant conversions along one or both dimensions?
> I’m glad to see you holding off until these related design issues are sorted out.
> Can you elaborate on what you mean by a corresponding Result<> type? I don’t follow the generic argument brackets without any arguments.
I was being intentionally vague about what the generic arguments to Result might be.
Evaluating a Swift expression always either yields a T or throws an E (or fails to terminate at all, but from a static perspective, we can ignore this). One purpose of Result is to allow the abstract result of that evaluation to be captured in a single value. It makes sense for Result to be parameterized by T, and possibly also by E.
Swift currently does not allow E to be constrained more precisely than just ErrorType. In this world, it makes sense to just be able to write Result<T>.
The point of typed “throws” is to allow E to be more constrained. In the simplest case, E might be one specific type; it might then make sense to be able to write Result<T, E>. However, there are more complex cases. For example, it might be possible to say (Java-like) that a function can throw any one of a set of different error types; would this have to be expressed as Result<T, E1, E2, E2, …>? That’s a tough fit for the generics system, especially since the error types are logically a set, not a sequence. Now, you could try to disallow this by saying that functions have to pick a single type that they can throw (e.g. ErrorType); but this doesn’t actually solve the problem, because expressions can contain multiple throw sites with different error types, so now you’ve got a set again. Again, you can force that back to the greatest common type (which will generally be ErrorType), but now Result loses information that normal type-checking would have preserved. So it’s a challenge.
> When it comes back up and assuming we have typed throws I would like to see support for multiple error types. I think it could be accomplished via an anonymous compiler generated sum type or something similar to that.
Structural sum types (as opposed to nominal sum types like Either which are explicitly formed and broken down) are a massive complication for type systems.
More information about the swift-evolution