Not sure if I can answer that on everyone else’s behalf. But I find it more useful than Either. I could be wrong and maybe a better name is there
Be careful that
Result is a fairly common term, certainly in wild
usage (at least, I use it in most of my projects, or declination of it).
Actually, I have a new convention to use
PureResult[A] as an alias for
Either[MyBusinessErrorSuperType, A] and
IOResult[A] as an alias for
ZIO[Any, MyBusinessErrorSuperType, A].
(see https://issues.rudder.io/issues/14870 for context / explanation and
a brief summary of the tooling built on that)
If you don’t really want to rename
Either, and are happy with its semantics, then I’m kind of lost on what you do actually want.
That was a typo, I am unhappy with the semantics.
Then how would the semantics differ from those of
This would fit nicely within the “Summer of Usability”.
One thing that makes Scala difficult for beginners is the lack of clear best practices. Error handling is just one of these cases. How do you return errors, the Scala way? Throw errors? Return a
Try? Or use the more general
Result type with distinct
Failure cases (and maybe some supporting infrastructure) that’s used in the documentation and the tutorials would allow neophytes to not have to worry about this. Advanced programmers can still use
Either or roll their own.
I think “Result” is very intuitive, but it’s not just the name that makes “Result” something significant in Rust. First, there’s language syntax to support Result. Second, and most importantly, Result is consistently used across Rust libraries, so you just can’t avoid becoming aware of it and how it is used as soon as you start doing anything in Rust. In fact, Result is covered early on by the two Rust books I’ve seen.
I’m still not clear on how this
Result type would differ from
Either other than by name – does it have different semantics, and if so, what are those?
Well, I’d argue that
Either doesn’t really have any semantics at all - it’s just a disjoint union. This is what is makes it difficult for beginners, since as a return type it doesn’t tell you what the “success” is and what the “failure”.
Right is success by convention (ans since 2.12 b bias), but you have to memorize “left is failure, right is success”. It’s not exceptionally bad, it’s a paper cut. But a paper cut that could be avoided.
Result type with distinct
Failure cases would provide these semantics.
I’m not yet sure how
Try would fit in. Maybe a opaque alias with some additional machinery? Why use
Try instead of
I think the whole error handling in Scala deserves some thought about best practices, as I mentioned before.
One may argue that instead of Either/Right/Left it may have been better to call it Result/Success/Failure. But now that it is already well established, what to do?
(1) Renaming it is quite disruptive.
(2) Duplicating it seems wasteful and confusing (“What’s the difference?”)
(3) Aliasing works, but, can be a little mental overhead or confusion, too
Regarding semantics: if you look at Either, it is immediately clear that it can be used for Success/Failure scenarios.
It’s less clear that not only can it be used for that purpose, but it is actually widely used for it, i.e. no other alternative has established itself like it.
Remembering which value is success and which is failure is easy: “The Right value is the right value!”
My take is:
We unfortunately got ourselves into a bad mess with
Either. It is extremely unfriendly to beginners and confusing on many levels. In my mind, once you got the basics wrong, any sort of patching up only gets you deeper in the hole. For instance,
Either.cond(condition, a, b)
condition is true it gives you the left alternative wrapped in a
Right, otherwise the right alternative wrapped in a
Left. To which the only appropriate answer is a long rolling “Riiiight”.
The original sin for
Either was right biasing it. Before,
Either could indeed be regarded as just a tagged union, and any code that used it otherwise was dubious. But right-biasing
Interesting aside: Why did people pick
Right for the result and
Left for error? I believe it is because Haskell does it this way. And why did Haskell do it this way? Because of curried type applications. The error type is often more stable than the result type, so you want more often a partial type application
Either E than its dual
Either R. But Scala does not have curried type applications, so the only reason to do it that way does not apply.
I believe our two choices are:
Eitheras the only official “result” type, accepting that users will be confused forever, and that our only explanation on why things are that way is “because Haskell”.
- Rip off the band aid, and introduce
Result. The only possible moment where this is a valid option is when we switch to Scala 3. But even then it is a daunting task. Nevertheless, I am seriously tempted to do it since for somebody like me who teaches Scala a lot the alternative of keeping
Eitheris so bad.
You could just deprecate Either.cond. It doesn’t seem very useful anyway. In any case even with a right bias there’s a valid argument for making the arguments go from left to right. Having to negate a boolean is not the biggest crisis to worry about.
Anyway, I don’t see any benefit to left-biasing it, and history aside, choosing or explaining a right bias does not require invoking Haskell. I really don’t understand the problem.
For anyone that wants a left-biased type:
type Else[A, B] = Either[B, A]
Now you can annotate all your methods
Thing Else Error if you like.
Incidentally, I don’t think Result is a good name for a general-purpose type. Types shouldn’t care whether you use them as an input or as an output. The way Play uses Result is fine in this respect, since it denotes an HTTP response, which is specifically an output. (Why it isn’t called Response is a separate matter.)
Either biased, my FP teachers used to tell us that it was because the right answer is
gauche, ie left in French, used to mean
bad - a root you find also in Italian
sinistra, and of course it was for extremelly bad social reason but well).
OK, so for the
Either case: in Scala 3, we will get real disjoint union with sum type. A built in
Either for that case is no longer needed, and I bet
Either is rather rarely used for union, even just because it is so much used for a return type.
Nonetheless, ditching it for
Result in scala 3 will be extremelly disruptive. It’s a very common name, most likely used in a lot of places (for ex see my comment above Pre-SIP: Proposal of introducing a Rust-like type "Result"). And of course, it will mean rewrite of most of scala projects (the number of projects which don’t use
Either directly or because of lib API might be small… But I may be biased, perhaps having data on that would be helpfull).
That being said, I believe it would be a good thing to do.
For the semantic, please don’t make it like
Try, ie let effects alone. If you want to deal with effect, please make
Result[E, A] isomorphic to
ZIO[Any, E, A], with a clear semantic to import effectful code into that result (ie
Result.effect(chunk): Result[Throwable, A]). But perhaps that we don’t want to standardise in the scala library something which is moving as fast as effect management in that
Result, which I would personnaly prefer, and so just change
Result (also: the migration in the case of effect-managing
Result would be extremelly hard because of the semantic change in presence of effects).
And then, a
Result[E, A] in the standard lib, any project will be able to do:
type PureResult[A] = Result[MyBusinessErrorSuperType, A] type IOResult[A] = ZIO[Any, MyBusinessErrorSuperType, A]
And things will be so much clearer
Doesn’t partial unification in Scala work similarly?
What exactly is the proposal? What would Result be?
Just a rename of
Either and related methods to make them result-y (
.mapLeft should become
.fold should behave correctly with inference, etc. )
I would also love to have some syntaxic sugar to have
.success) extension methods.
Yes, at least in Scala 2. The functor hole (i.e., the type parameter for success values) needs to be rightmost. (See SI-2712 for rather more detail, if you’re reading along and don’t know what we’re talking about.)
As far as I can tell we’re either (heh) asking for exactly
Either with different names, or maybe something like
cats.data.Validated which is isomorphic to
Either and exists only to select different typeclass instances (accumulating applicative instead of fail-fast monad … but I think the error-accumulating behavior will be awkward in vanilla Scala without applicative syntax, i.e., cats
mapN). In any case I couldn’t find a post with an actual proposal so I’m not 100% sure what we’re discussing.
My position for the moment is I don’t probably care as long as we keep
Either as-is (monadic, right-biased) and provide
.toResult to convert between the representations.
Dotty does the same.
Just my 2 cents. Either is perfectly fine, and it’s been right-biased since 2.12. Leave it be and don’t introduce additional complexity by adding a new type with the exact same semantics. We have much bigger fish to fry.
Holy S$#%!! In the amount of time we’ve spent debating this issue a small OSS library could have been written! Or all the needed adaptors from whatever implementation of Try/Either to whatever the heck else we want with similar functionally could have been written! Maybe let’s be a bit more pragmatic!?