Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I've always thought that the Left and Right naming in the Either type was a poor choice in Haskell. Left and Right don't convey any semantics at all and I constantly need to spend mental energy on remembering which is the Ok and which is the Error (speaking in Rust Result terms). Sad to see that people are translating these naming mistakes into JavaScript.

The underlying error handling methodology however is awesome and I miss its guarantees and composability in my daily C++ work (yes I know, there's Boost Outcome, but they stripped it of everything useful before including it in boost, as far as I'm concerned).



A mistake easily corrected. They do convey the exact meaning well. It's the analogy that appeals to your intuition which is wrong.

    Either a b === a || b
Where `===` means equivalent to. This means that a value of the type can hold either the `a` or the `b`. In order to construct a value of this type you used the `Left` function to construct a value contain the value on the left side of the operator and Right for the other side.

They have no "semantics" otherwise. You could call them "Jib" and "Jab," and it'd amount to the same thing. Simply because you ascribe a particular meaning doesn't change their nature. Hence why Left and Right.

Now I do recommend, for readability's sake, ascribing an alias to this type if it aids your understanding of the code when you use it in a particular way that gives your code a certain meaning!


I think they're saying he would prefer some semantics - like one is the preferred or normal case, and the other is an error or unexpected case.

They might convey the exact meaning well, but they (and I) would prefer a type with slightly different semantics that better remind us what each side actually represents.


Did you catch about what OP was saying though? Instead of Normal and Unexpected they are recommending you write something like:

    const ChargeSuccess = Left
    const ChargeDeclined = Right
And then use that language in your code. Those words tell you something about the semantics of the code being wrapped. “Normal” and “Error” don’t actually mean much.

Also, you might want to someday write:

    const NormalDelivery = Left
    const FastTrack = Right
And that wouldn’t make much sense if fast track is a so-called error condition.


I did see that. This is a common pattern in many functional languages, and (for example) Scala has the same issue with Either. It's a common enough complaint that there are numerous right-biased utility versions in the wild that make it more ergonomic.

Having a type that is right biased doesn't mean it can't also implement the more generic interface. If your needs change you can always go back to using the less opinionated version with little breakage.

Rust's is notable in that they have both Either and Result. I think there's value in that, even if it is mainly for ergonomics and communication.

Also, aliases are fine, I could just see them being duplicated a lot. Probably not my first choice.


> Rust's is notable in that they have both Either and Result. I think there's value in that, even if it is mainly for ergonomics and communication.

either isn't in std though, it's a third party crate. Personally, I think the core data structure should be as generic as possible. The reality is that if the Result type was named appropriately, the Either crate would be redundant.


Rust's "generic as possible" type is an enum. Result is a specialization meant for common error handling.


> Rust's "generic as possible" type is an enum

What enum? We're talking about a specific data type, it doesn't make any sense to say 'an enum' is the generic version of Result.

I understand why they chose Result instead of Either. I just disagree with it; what you end up with is 2 data structures with the exact same structure and implementations but that represent different things. If you have Either in std, then Result is redundant, but not the other way around.


What Result? Result is a generic not a specific type. It's essentially a shorthand instead of manually writing out the enum yourself.

More fundamentally I disagree that Either makes Result redundant. Result has semantic meaning that's lost with Either.


> What Result? Result is a generic not a specific type. It's essentially a shorthand instead of manually writing out the enum yourself.

No, it's not 'a generic', but it has generic type parameters. An enum can be any number of variants with any number of type parameters.

A result is: data Result a b = Err a | Ok b (or in Rust) enum Result<T, E> { Err(E), Ok(T) }

> It's essentially a shorthand instead of manually writing out the enum yourself.

I'm not sure which enum you're referring to. You do realise an enum can have any number of variants, not just 2? I could define a sum type with 16 variants. 'enum' is just Rusts keyword for defining sum types.

> Result has semantic meaning that's lost with Either.

Which is what?


> You do realise an enum can have any number of variants, not just 2?

Yes, that's what makes it more generic than Result. Indeed that's the only practical difference except for a few helper functions and a #[must_use] (which only makes sense for Result, not for a more general Either type).

>> Result has semantic meaning that's lost with Either.

>Which is what?

Seriously? Error checking! That's the whole point of it. One side has meaning over the other; it has weight. The "left" is the result you want. The "right" is when something gone wrong.


> Yes, that's what makes it more generic than Result. Indeed that's the only practical difference except for a few helper functions and a #[must_use]

I think you have some fundamental misconceptions about sum types. Note that enums also don't even need to have any variants.

enum Never {}

Either way, this discussion is no longer fruitful. I encourage you to read about sum & product types.


Or, to put that another way, Either is "cons" for types, and you can build up a sum type as a type-level linked list of types by repeatedly "cons"ing (Either-ing) types together: (a || b || c || ...). The functional-programming traditionalist would call the type-level "slots" of an Either its "CAR type" and "CDR type".

But, since there's no abstraction that assumes that such a structure of sum-types is shaped like a proper list, there's nothing stopping you from building any arbitrary binary tree of types using Either. And so, like any other binary tree, the two branches get called Left and Right.


There definitely are more semantics than this in the monad instance for Either, which treats Left as "failure" (via early exit in a comprehension) and Right as "success". The docs call out the convention as well.


The way I remember is that the Romans associated the left with bad things, with this ultimately making its way into English in the word "sinister" [1]

As this association was extended to left-handed people, its use nominally perpetuates an ancient slur, but I think we can put that aside.

[1] https://english.stackexchange.com/questions/39092/how-did-si...


Bingo. A left handed person is sinistrous, a right handed person is dexterous.

An interesting place this is preserved is in heraldry[0], and I've also heard it used in cards (a King, in red, facing the dexter).

[0] https://en.wikipedia.org/wiki/Dexter_and_sinister


Yeah, I've heard the mnemonic "an Either contains either the Right answer or else whatever's Left", which is simple/punny enough to be memorable.


That perfectly captures what it does too. Nice one.


And here I've just been using the fact that "right" also means "correct" in English


I never thought about it before, but I wonder if there is a connection? - along the lines of "correct" and "just" (in the sense of ethically correct) being the opposite of bad / evil? Some people here [1] think so, but "right" appears to have Germanic roots (but then again, perhaps the idea of right/good and left/bad may predate the Romans, and maybe goes back to the time of proto- Indo-European, or even further.)

"Right" also has the meaning of "upright" (as in right angle) or, archaically, as "straight", and the normal processing path might be regarded as the straight one in the railway metaphor.

[1] https://www.reddit.com/r/etymology/comments/2cdshk/etymology...


There is a connection it's just that the 'right-as-not-left' bit is the newer development.

https://www.etymonline.com/search?q=right


I usually just treat it as a pun between "Right/Left" and "Right/Wrong".


Interesting, thanks for explaining.


> I constantly need to spend mental energy on remembering which is the Ok and which is the Error

Right is actually a synonym for Ok.. besides, Either is useful for _much_ more than error handling. That is exactly why I dislike Error for the left side; often it's just not an error.


TFA had so many parentheticals and explanatory comments on this that it would have been shorter if it used "Sad" and "Happy" instead. Of course, if brevity had been a goal there would also have been some inheritance...


I may actually use that. That's a great metaphor.


The naming is totally mnemonic.

If all went well, the result is Right.

If something went awry, you can still examine what's Left.


They are named like this because you can use it for more than just errors, it just so happens that it's a good fit for errors. In fact, I wish Rust had named it Either, instead it's called Result (with Ok/Err variants). This is great for errors, but it leads to the creation of (https://crates.io/crates/either) because there are scenarios where you want Either and the Err/Ok name is too presumptuous.

A good way to remember which variant represents success in the case you're talking about an error is that Right is the "right" variant, Left is the "wrong" one.


To my mind the problem isn't so much having Either as using it as Result - which I agree was unfortunate. In the same way that fst and snd don't tell me much about a tuple.

At least there's a pun (right vs. left, right vs. wrong), which is probably why the pattern stuck, but I don't think that's actually sufficient justification.


I remember it by thinking that Left (error state) has to be handled first. This forces developers to always think of the erroneous state first and foremost. And then define the Right (success state).

On the other hand, it may be easier to forget the error state if it were the second argument. As is often the case with Promises and JS developers.


Yes it's terrible naming. The more abstract the naming, the harder it is to reason about. Plus, JS/TS already have proper union types without a need for a construct like Either.

A better naming for 99% of cases is (like found in Elm)

type Result error value = Ok value | Err error


Plus, JS/TS already have proper union types without a need for a construct like Either.

I disagree - what if on success it returns a string representing some data, and on failure it returns a string detailing the error? A `string | string` return type is not very useful, while an `Either<string, string>` is IMO.


But that's the simplest union type.

You could have:

type Result = {type: 'ok', value: string} | {type: 'err', value: string}


I think the point is there is no inherent meaning. It is just two possible results. Could be an error, could just be another likely path. Will only be one of them, though.


But there is a difference in meaning. Left shortcuts, Right doesn't.

It would be bad to name it after error handling, but the entirely meaningless names aren't great either.


Left only shortcuts because of the implementation of the map function. There could just as easily be mapLeft and mapRight functions instead, allowing you to choose the shortcut behaviour.


I don't think there's any documentation on Haskell's Either monad that doesn't explain that Right=Good even if it's only by convention. But its functions also has right affinity, so Right and Left cannot have equal weights. You have to decide why this result is in the right/default slot over the other one.


But Either is also a Bifunctor so you CAN do to the Left what you do the the Right as well as unpacking the value from both sides.


I agree that Either is more general than error handling, but it's widely used for that in practice. The original article uses it for that, too.


The left one is always the error because the right is the right one.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: