A function returns a Result. This concept in Rust is so ubiquitous that it should be a first class citizen. It should, under all circumstances, be syntactically implicit:
```pub fn better->self```
No matter what it takes to make the compiler smarter.
That is not, in fact, a core concept in Rust. Plenty of functions have no reason to return Result. (And some that do also have a reason for the inner class to be a result.)
> This concept in Rust is so ubiquitous that it should be a first class citizen. It should, under all circumstances, be syntactically implicit:
“Implicit” is an opposed concept to “first-class citizen”. Result is first-class in Rust, and would not be if function returns were implicitly Result.
If you don't see std::result::Result as a core concept in Rust, which might be fair, one can still argue that it _should_ be a core concept, given its ubiquitous usage.
You misquoted, I never said Result is not a core concept.
What I said is that “A function returns Result” in the universal sense (that is, everything that is a function returns Result) is not a core concept in Rust.
Some functions return Result<T,E> for some <T,E>. Some functions return Option<T> for some T. Some functions have no reason to use that kind of generic wrapper type (a pure function that handles any value in its range and returns a valid value in a simple type for each doesn't need either; Option/Result are typically needed with otherwise non-total functions or functions that perform side effects that can fail.)
> I remain convinced that the whole Result concept was just created by people butt-hurt over the concept of exceptions
I wouldn't use the emotionally-loaded dismissive language, but, yes, Result is a solution to the same problem as exceptions that deals with several problems of exceptions, including:
(1) Unchecked exceptions obscure what is going on, and frustrate analysis because things remote from the code may bypass it in the call-stack without any evidence visible in signatures.
(2) Checked exceptions are clear, but create a separate syntax for expressing type-like constraints, also limiting what you can do around them because they aren't the same thing as types.
The sad part is that Rust still has exceptions, they're just called panics.
I love Rust to death, but I feel this is a huge flaw in its design. Writing any unsafe code that takes a callback function is a massive pain in the ass, because anytime you call this callback, it could panic, so you must restore into a safe state if stack unwinding occurs.
For example, I'm currently writing a fast sorting algorithm, using mostly unsafe code (by necessity). Every time I compare two elements, a panic could occur, and all elements have to be placed back in the input array to restore to a safe state. It's hellish.
There is the panic = abort flag which is great if you're writing a binary. But as a library you can not assume this.
I'll certainly grant that unchecked exceptions are problematic for static analysis, but in regards to your second point, I don't feel like Rust has actually avoided creating "a separate syntax". It's created a different, more complex syntax which must be adopted inline in your actual normal code path, obfuscating what your code is actually expected to do under non-error conditions.
IMO, one of the most valuable pieces of exception handling is a distinct separation between your error logic and your non-error logic, which makes methods easier to comprehend. I also feel like the existence of the ? syntax is a dead giveaway in this regard because it's a fig-leaf trying to cover up the most egregious parts of the code where you'd otherwise have to be write the frequent "if error then early return error" statements which plague Golang.
The main reason behind the panic/Result distinction is that systems programmers, particularly those working in embedded, want to be able to turn off unwinding support entirely. Unwinding adds control flow edges everywhere, inhibiting optimizations, and it either adds code size bloat for the unwind tables or runtime overhead at every function call, depending on how it's implemented. I don't know of any way to implement exceptions that doesn't have this overhead. So although I like exceptions myself, I agree with Rust's decision not to embrace them in its domain.
> but in regards to your second point, I don't feel like Rust has actually avoided creating "a separate syntax"
It avoids creating a separate syntax from the usual return-type declaration syntax for declaring the existence of errors, when compared to checked exceptions.
It also avoids creating a separate syntax for error handling, compared to (checked or unchecked) exceptions (pattern matching is ubiquitous in Rust for other purposes).
> It's created a different, more complex syntax which must be adopted inline in your actual normal code path, obfuscating what your code is actually expected to do under non-error conditions.
Pattern matching isn't an additional syntax (indeed, many languages with exceptions also have it), and it (IMO) does less to obscure non-error code than the visual noise of handling errors with try/catch.
It is more visual noise in the case of functions that do the equivalent of not handling exceptions, compared to exception-using langauges where that is implicit.
This would break the principle that you always know how to invoke a function by looking at its signature. Option of T and Result of T are not the same type as T. You would have to look at the body of the function, or rustdoc, to know how to invoke it, which would be very annoying.
Besides, what is the error type for Result? You haven't declared it.
Others have addressed the problem with "implicit", but I might be on board with "lightweight"; maybe in a type context `T?` can mean `Result<T>` for whatever Result is in scope? That way you can still define functions with various distinct error types the same as today, but the common (idk just how common, not claiming a majority) case of using the same error across a module or package with a Result type alias will get cleaner.
That's a good point, but I am not sure it would actually be a problem.
For one thing, we already have syntactic collisions that don't seem to cause much problem (consider `foo?.bar` in .ts vs .rs), and this one would probably be prevalent enough that it would quickly be familiar to anyone using the language.
For another, if we squint I'm not sure those other languages aren't "really" using it for the same thing. If in some module we define `type Result<T> = Option<T>` then we have the same behavior in Rust, and we can imagine that those other languages have basically done so implicitly, meaning it's a less flexible version of the same mechanism (put to slightly different purposes).
```pub fn horror()->Result{Ok(Result(mut &self))}```
A function returns a Result. This concept in Rust is so ubiquitous that it should be a first class citizen. It should, under all circumstances, be syntactically implicit:
```pub fn better->self```
No matter what it takes to make the compiler smarter.