[swift-evolution] [proposal] Either in the Swift Standard Library
devteam.codafi at gmail.com
Tue Jan 26 23:09:07 CST 2016
I’m going to try and round up a summary of arguments for and against this proposal and my response to them, because I think there is a clear sense in everybody’s mind what Either entails, but that sense differs widely depending on individual interactions with the parts of the proposal. I take full responsibility for the rhetoric and the style of debate that has been going on for the past ~24 hours. It was borderline unprofessional the way this was going and I want to apologize now to those involved for being so very unclear in my reasoning and my rhetoric as to stir up a senseless debate about points we essentially agreed on beforehand. As such, I’ve made some revisions to the proposal, I request that you all please re-read it (at https://github.com/typelift/swift-evolution/blob/either-or/proposals/0024-either.md) before we try again so we can refocus this debate on more productive avenues of discourse.
Throughout this reply I’ve made heavy use of quotes from other replies. Those will appear in purple. Quotes from the proposal will appear in blue.
The type “Either” that we describe in the proposal is a placeholder. I feel that must be emphasized, because there have been arguments about the name. We specifically mention this in the proposal:
> The Swift Standard Library will be updated to include a left-biased sum type we have called Either - though other names may be appropriate depending on how the type is implemented.
What we are requesting is a finite-case, here precisely two-case, type that represents two disjoint possibilities. As noted before, this type is often called Result by Swift framework authors and notably the programming language Rust which uses it in place of an exception handling mechanism.
> Your motivating examples (including all the projects you linked except "Any many more") overwhelmingly use the Either (or similar type) to represent success/failure. I'm not sure there's a single example where the names Left and Right actually make sense in the problem domain.
> There absolutely is a cost. `Result<T>` has a rather intuitive meaning. `Either<T>` has no intuitive meaning whatsoever. It says absolutely nothing about what it means beyond the fact that there are two potential values. As a result, it is a largely useless type whose sole redeeming feature is it allows developers to avoid having to define their own enum, but in most cases that aren't covered by Result<T> you actually want to define your own enum so you can attach meaning to the value.
> You've mentioned Rust many times, but I don't understand why. Rust does _not_ have an Either type. In fact, Rust's success is a great example of how Either is unnecessary. What Rust does have is a Result<T,E> type, and the lack of a more generically-named Either type was an intentional decision (with pretty much the same rationale that I've been giving).
We recognize that Result conveys a particular semantics that encourage this type to cross over into the error-handling domain. As noted in the proposal, we don’t want to emphasize this case because a version of this proposal was already rejected for overlapping too heavily with throws. If the community feels that the proposal deserves to be rewritten in a way that re-emphasizes this case and makes that point then I am up for it. But, I request that this not be used as an argument to reduce the genericity of the type - which is to say I don’t wish to see a Result<T> or a Result<T, E : ErrorType> because they reduce the power of the original proposal.
When I use the term genericity, I am not arguing for the naming scheme of the Either we have, I’m arguing for the structure to be kept around as-is. My biggest fear is that a Result with one lobe and an Error is going to be merged rather than the full proposal because this type and the discussion of it outside of here can become too absorbed in the error-handling case. I do not wish to lose the structure of the type we have now, because that structure is precisely what a future Swift could generalize and abstract upon. The name, however, is up for grabs. We offer a list of alternatives at the end of the proposal, if you have any more to suggest please reply to me here and I’ll see about adding them.
At the same time, it has been brought up that Either conveys no immediate useful information. At the time of writing this proposal, we do not believe that to be the case, but we recognize that by naming this Result we can reach a wider audience. At the end of the day the proposal is about merging in a 2-case sum type. We chose Either not because we wanted to see it merged, but precisely because it was so meaning-agnostic. It’s our lorem-ipsum. For those that think we’re trying to merge a Haskell-ism, I can say with complete confidence that no part of TypeLift intended that in the original proposal. Whatever bad taste Haskell may have left in anybody’s mouth, the Either in our proposal is a placeholder for a name to be decided upon by the community. I felt that this was clear from the line
> though other names may be appropriate depending on how the type is implemented.
> In addition, the name `Either` does not lend much to the imagination,
> and the use of `Left` and `Right` have the potential to cause confusion to
> novices expecting a `Result<T>`
in the original proposal, but I was wrong. I have updated the draft accordingly.
Besides, even if the type in the proposal were to be merged right this very second, “meaningless" names and all, a domain-specific Result type could easily be recovered from it. The same is not true of a type that is immediately domain-specific like the reduced-generic forms of Result. To translate that into the language of Result using Either as a template: If a Result<T, E> were not merged, then it could not be recovered from Result<T> in any meaningful manner. However, a constrained Result<T, E : ErrorType> can be recovered from the fully generic type in the proposal.
> I agree with Kevin and others that we’re likely to be destined to introduce a real Result type. This will serve the most common cases that you’re citing as use cases for a fully generic Either type, and provide good names. Why should we add a type to the standard library that has very few remaining use cases, and leads to a code style that we don’t want?
This is in line with the goals of the proposal and I would certainly support this renaming if it serves the community’s best interest. You all are, by now, aware of my qualms with the name, but I’m not one to dwell on these things when we’ve made it clear in the proposal that the type can go by many names. It’s the structure of a sum that we’re after, and we’re willing to take it how it comes - but contingent on the shape of the type not differing from the proposal as written. I request that if the name Result be brought up again, that it come with the specific number and kind of parameters involved so we can nail down the shape being discussed.
> The argument is often made that we should have a generic “Either” type (though the name doesn’t matter, I’m talking about the semantics you’re describing) to complement tuples. However, the Either type you are providing is not analogous to Swift tuples, because Swift tuples allow you to *name* the elements of the tuple, and is generic w.r.t. the number of elements. Your Either type has neither of these features.
Contrary to the impression the other discussion has made, nowhere in the proposal do we wish to augment the type system. If this is done correctly, the type in the proposal should be a ~40-line addition to the standard library, it should not wind up as a full-blown language change. We are not advocating for an n-element sum type, nor are we arguing for a structural typing scheme that would put variadic sums in the language because we recognize that solution is untenable. We are, however, advocating for the inclusion of a 2-case sum type we happen to call Either in writing.
> The type system already supports N-ary “either” types. We call them enums.
> This is another example of exactly why Either is terrible in practice. I understand that from a type algebra point of view this is perfectly reasonable and clean and that a 2-way sum is all that is necessary because larger sums are easily created by construction. Type theory-wise it’s lovely.
Because this is a non-goal of the type. The sum as presented in the proposal does not attempt to take the place of enums, nor does it make any bones about being a finite entity. We are specifically emphasizing the two-element case. Any other arguments that pertain to its inclusion as a feature of the type system should start at the last site of discussion and probably terminate in a separate proposal adding that kind of scheme to the Swift language itself. We are arguing for a simple change to the standard library, nothing more.
> As before, unlike `throws`, a disjoint union type can be applied in arbitrary
> positions, used as a member, and easily checked for completeness
> at compile time. In addition, the lack of a standard union type has
> led the Swift community to create [numerous](https://github.com/search?utf8=✓&q=Either+language%3Aswift) duplicate implementations of the
> same mutually incompatible types over and over and over again. In the
> interest of promoting a type that there has received clear interest by the
> community, the addition to the Standard Library is necessary.
The argument is not “let’s toss out all implementations of 2-case enums in favor of this sum” it’s “very often, when you’ve got a two-case enum with bias, you’ve got a sum described in the proposal”. This pattern shows up in a sufficiently large number of cases that we feel that the standard library deserves to have the final say as to a community-guided implementation of this type because individual implementations seem to differ only in a few minor places like naming or generic positions.
> I perceive a common Result/Either type as being desired for composability. If I have two libraries that define their own Result/Either/etc. types, my ability to compose functions across those libraries is impacted.
This is another motivating factor that lines up with a major tenant of the proposal. We would not be suggesting this change to the standard library if we did not see this pattern show up in a number of large frameworks, applications, and everything in between. We offer a section of motivating examples and links that should convince you of its commonality if that is still a sticking point.
> I’d say “works”, not works; the ergonomics are terrible, you are unlikely to be able to take advantage of the bias anymore, and even if we overlook all that, you still have to enforce an external convention to get mutual-interoperability at each n; otherwise, you may say Either<Either<,>,Either<,>> but I may say Either<Either<Either<,>,>,> and someone else may say Either<,Either<,Either<,>>> and someone else says Either<,Either<Either<,>,>> and so on…
This point, while valid, is also an unfortunate feature of Optionals as well, which I have argued can be viewed as an Sum with one lobe “sealed” by Top, the empty tuple. I have yet to see a use of a sum type that needs nesting like this, nor have I seen any type or type alias that attempts to use this to recover an n-ary Sum because it just doesn’t happen. If you have a disjoint set of possibilities with order greater than two, as Chris noted, Swift already offers enums. And if such a case has arisen, it needs to be refactored just as Optional<Optional<Optional<...>>> would be.
> * An either-like type should be named something meaningful for the context it is used
> * There are a lot of cases where an either-like type is useful, there may generalised functions that are often used on them
> * Is defining or re-defining an either type hard?
> * Is it too niche to be in the standard library
We don’t believe so, see proposal.
> No, I take issue with the entire fundamental idea behind your proposal. You've explicitly defined this type purely by its shape, with no meaning whatsoever given to either variant, except insofar as the type is Left-biased (which only serves to be even more confusing; since there's no actual meaning assigned to Left/Right, what is the justification for adding the left-biasing?)
The rationale given for bias has been updated in the latest draft.
> I agree with Kevin and others that we’re likely to be destined to introduce a real Result type. This will serve the most common cases that you’re citing as use cases for a fully generic Either type, and provide good names.
> On Jan 20, 2016, at 10:17 PM, Developer <devteam.codafi at gmail.com> wrote:
> Hey all,
> Just added a section of motivating examples to the Either proposal. Ping me if you have any more that I missed ('cause I'm sure I did miss a lot).
> ~Robert Widmann
> 2016/01/09 14:19、Developer <devteam.codafi at gmail.com> のメッセージ:
>> Because the last discussion, while substantive and very much appreciated, did not debate the proposal much, I'd like to begin discussion anew about the addition of an Either type to the Swift Standard Library. The proposal can be found here (https://github.com/apple/swift-evolution/pull/67#issuecomment-170269481) and a link to the root our previous round of discussion is here (https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20151207/001394.html).
>> Thanks all!
>> ~Robert Widmann
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the swift-evolution