Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Library] enum Fallible on std #3395

Open
igotfr opened this issue Feb 25, 2023 · 12 comments
Open

[Library] enum Fallible on std #3395

igotfr opened this issue Feb 25, 2023 · 12 comments

Comments

@igotfr
Copy link

igotfr commented Feb 25, 2023

pub enum Fallible<T> {
  Succ,
  Fail(T),
}

how Option is equivalent to Result<T, ()>,
Fallible is equivalent to Result<(), T>

https://datavirke.dk/posts/fallible-missing-rust-error-handling/

@lebensterben
Copy link

This article you linked has a wrong understanding of unit type.

The author thinks the unit type is of no value, hence the success case of Result<(), E> contains no value. This is wrong.

A fact that the function returns already contains information. When the returned value is a unit type, it's simply that there's no additional information. But the information is already conveyed by the fact that it returns.

So it's pretty obvious Result<(), E> is perfectly right for the use case.

@digama0
Copy link
Contributor

digama0 commented Feb 25, 2023

I don't think the article has any misconceptions about that, and the table is correct. But I also think that it is 8 years too late to be proposing something like this; the value of these kinds of types lies in their ubiquity and there is no way Fallible will ever gain that kind of traction. Option and Result have been in Rust from day 1.

I think it would be a bad idea to add something like this to the prelude, and lose names like Succ and Fail in user code. The meaning of this type is still essentially a success-or-fail, meaning that it will want to use the same terminology as Result and will largely overlap with it. Who wants to learn that failures return Err, unless the function doesn't return a success result in which case you should spell it Fail?

I think the only reasonable version of this would be if you had type Fallible<T> = Result<(), T> and const Succ: Fallible<T> = Ok(()), but that likely doesn't deliver on the main goals discussed in the article in the first place because it isn't first class in the same way as Option and Result.

@SOF3
Copy link

SOF3 commented Feb 25, 2023

If anything, it'd make more sense to have type Option<T> = Result<T, ()> instead. Maintaining the parity between Option and Result is costly.

@igotfr
Copy link
Author

igotfr commented Feb 26, 2023

This article you linked has a wrong understanding of unit type.

The author thinks the unit type is of no value, hence the success case of Result<(), E> contains no value. This is wrong.

A fact that the function returns already contains information. When the returned value is a unit type, it's simply that there's no additional information. But the information is already conveyed by the fact that it returns.

So it's pretty obvious Result<(), E> is perfectly right for the use case.

unit contains one value, but in this case, a useless value

@igotfr
Copy link
Author

igotfr commented Feb 26, 2023

I don't think the article has any misconceptions about that, and the table is correct. But I also think that it is 8 years too late to be proposing something like this; the value of these kinds of types lies in their ubiquity and there is no way Fallible will ever gain that kind of traction. Option and Result have been in Rust from day 1.

I think it would be a bad idea to add something like this to the prelude, and lose names like Succ and Fail in user code. The meaning of this type is still essentially a success-or-fail, meaning that it will want to use the same terminology as Result and will largely overlap with it. Who wants to learn that failures return Err, unless the function doesn't return a success result in which case you should spell it Fail?

I think the only reasonable version of this would be if you had type Fallible<T> = Result<(), T> and const Succ: Fallible<T> = Ok(()), but that likely doesn't deliver on the main goals discussed in the article in the first place because it isn't first class in the same way as Option and Result.

8 years ago very few people knew Rust, I was just starting to learn programming with C and PHP

I understand the difficulties in implementing, but to say that Succ and Fail can't be added to prelude presuppose that nothing more can be added to prelude, it's the case?

@igotfr igotfr changed the title enum Fallible on std [Language] enum Fallible on std Feb 26, 2023
@digama0
Copy link
Contributor

digama0 commented Feb 26, 2023

I don't think the article has any misconceptions about that, and the table is correct. But I also think that it is 8 years too late to be proposing something like this; the value of these kinds of types lies in their ubiquity and there is no way Fallible will ever gain that kind of traction. Option and Result have been in Rust from day 1.

8 years ago very few people knew Rust, I was just starting to learn programming with C and PHP

That wasn't directly aimed at you (obviously everyone has their own circumstances), but rather the proposal itself: Rust too stable now to be able to make foundational changes like this anymore. A proposal that tries to make Fallible a completely new type with a parallel API will not work because there is a whole ecosystem that would have to adapt to it, and in many cases that would mean breaking API changes in places where breaking changes are unacceptable.

I understand the difficulties in implementing, but to say that Succ and Fail can't be added to prelude presuppose that nothing more can be added to prelude, it's the case?

No, but the bar for getting things into the prelude is very high. So far the prelude has only changed once, for the 2021 edition, and even then most of the originally planned additions were cut before the release; and everything considered was already in std and used widely in the ecosystem. Going from nothing at all to in the prelude is a huge jump and would take many years.

@igotfr igotfr changed the title [Language] enum Fallible on std [Library] enum Fallible on std Feb 26, 2023
@igotfr
Copy link
Author

igotfr commented Feb 26, 2023

@digama0 I meant that at that time Rust was irrelevant in a broader context (break changes weren't a problem like they are today) and influenced by few people, much less than today

Well, it's the Haskell's lemma of not being popular, Rust is getting more bureaucratic, that was good, but now is difficulting its improvement

@digama0
Copy link
Contributor

digama0 commented Feb 26, 2023

@digama0 I meant that at that time Rust was irrelevant in a broader context (break changes weren't a problem like they are today) and influenced by few people, much less than today

Right. That's why such a change would have been okay then, but not now, even if the proposal were exactly the same.

But even setting that aside, assuming we could magically solve the compatibility and ecosystem issues, I think there are other significant issues with the proposal like having Err and Fail which are synonyms and would confuse newcomers, in addition to refactoring / inlining functions returning Result<T, E> into Fallible<E> and back now having additional overhead because if the return value changes then you have to change all the Err to Fail and Ok to Success.

Another way to put it: Option and Result are monads, Fallible isn't. This means that Result handles composition better than Fallible, and it is also an explanation for why it doesn't show up in ML or Haskell and why Rust inherited the same legacy. For Fallible to have an and_then operator, it would need to use Result for some of the intermediates, but if they are () then you want to use Fallible instead, so that's ... 4 different versions of and_then? The naming would be a mess, and switching from one to another on a refactor would also be annoying. And why, when we have generics and a perfectly good instance of Result to use to cut down on the duplication?

@igotfr
Copy link
Author

igotfr commented Feb 26, 2023

@digama0 why Fallible can't be a monad?

@digama0
Copy link
Contributor

digama0 commented Feb 26, 2023

A monad is a type constructor M<T> with an operation pure: fn(T) -> M<T>, and_then: fn(M<A>, fn(A) -> M<B>) -> M<B> and some laws. Now Fallible<T> is also a type constructor so maybe you might consider to take M<T> := Fallible<T>. One of the monad laws is pure(x).and_then(f) = f(x), which implies that pure(x) = Success would not work, and pure(x) = Fail(x) would imply that and_then runs the failing result and not the successful result, making it equivalent to Option and not having the desired short-circuiting behavior on ?.

@Aloso
Copy link

Aloso commented Jul 19, 2023

I would say that Option and Result have completely separate use cases, and thinking about Option<T> as an equivalent for Result<T, ()> is a bad idea.

  • Result is used for error handling.

  • Option is used when a value may or may not exist.

For example: Iterator::next returns an Option to indicate that a next item may not exist. The absence of a next item is not an error; it just means that the iteration is finished.

Likewise, Some does not imply success. For example, an error may contain an Option<Backtrace>. If it is Some, then we have more information about the error, but it is still an error.

@coolCucumber-cat
Copy link

I would say that Option and Result have completely separate use cases, and thinking about Option<T> as an equivalent for Result<T, ()> is a bad idea.

They aren't saying they have the same use case or that they are the same thing, they are saying that they have the same footprint and are interchangable. They both convey the same amount of information. The unit type conveys no extra information other than that exists, just like the None variant. You can convert any Result<T, ()> to an Option and vice versa without any data loss.

Basically, Option could be a type alias for Result<T, ()>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants