Result type
This article needs more citations. (January 2021) |
In functional programming, a result type is a monadic type holding a returned value or an error code. They provide an elegant way of handling errors, without resorting to exception handling; when a function that may fail returns a result type, the programmer is forced to consider success or failure paths, before getting access to the expected result; this eliminates the possibility of an erroneous programmer assumption.
Examples
[edit]- In C++, it is defined by the standard library as
std::expected<T, E>.[1] - In Elm, it is defined by the standard library as
type Result e v = Ok v | Err e.[2] - In Haskell, by convention the
Eithertype is used for this purpose, which is defined by the standard library asdata Either a b = Left a | Right b, whereais the error type andbis the return type.[3] - In Java, it is not natively in the standard library, but is available from third party libraries. For example, result4j which includes an interface
com.github.sviperll.result4j.Result<R, E>similar to RustResult<T, E>, and vavr includes an interfaceio.vavr.control.Either<L, R>similar to HaskellEither a b. Because Java and Kotlin are cross-compatible, Java can use thekotlin.Result<T>type from Kotlin. - In Kotlin, it is defined by the standard library as
kotlin.Result<T>.[4] - In OCaml, it is defined by the standard library as
type ('a, 'b) result = Ok of 'a | Error of 'b type.[5] - In Python, it is not natively in the standard library, but is available from third party libraries such as returns and result.
- In Rust, it is defined by the standard library as
std::result::Result<T, E>, an enum withOkandErrcases.[6][7] Additional aliases inside other namespaces exist, such asstd::io::Result<T>(which is an alias forstd::result::Result<T, std::io::Error>). - In Scala, the standard library also defines an
Eithertype,[8] however Scala also has more conventional exception handling. - In Swift, it is defined by the standard library as
@frozen enum Result<Success, Failure> where Failure : Error.[9] - In V, the result type is implemented natively using
!Tas the return type of a function. For examplefn my_function() !string { ... }. Error Handling in V.
C++
[edit]The std::expected<T, E> class uses std::unexpected() to return the type E, and can return T directly.
import std;
using std::expected;
using std::ifstream;
using std::string;
using std::stringstream;
using std::unexpected;
using std::filesystem::path;
enum class FileError {
MISSING_FILE,
NO_PERMISSION,
// more errors here
};
expected<string, FileError> loadConfig(const path& p) noexcept {
if (!std::filesystem::exists(p)) {
return unexpected(FileError::MISSING_FILE);
}
ifstream config{p};
stringstream buffer;
if (!config.is_open()) {
return unexpected(FileError::NO_PERMISSION);
}
buffer << config.rdbuf();
config.close();
return buffer.str();
}
int main(int argc, char* argv[]) {
path p{"configs/my_config.txt"};
if (const expected<String, FileError> s = loadConfig(p); s.has_value()) {
std::println("Config contents: {}", s.value());
} else {
switch (s.error) {
case FileError::MISSING_FILE:
std::println("Error: path {} not valid or missing!", p);
break;
case FileError::NO_PERMISSION:
std::println("Error: no permission to read file at path {}!", p);
break;
// additional cases...
default:
std::unreachable();
}
}
}
A tag std::unexpect (of type std::unexpect_t) may be used to directly construct an error state inside a std::expected.[10] A specialization for std::expected<void, E> exists for when a function does not return any data upon success. If the value() method is called on a std::expected that contains an error, a std::bad_expected_access exception is thrown.[11]
Rust
[edit]Enums in Rust are tagged unions, which can be unpacked with strong type checking through pattern matching. The Rust expected type is std::result::Result<T, E>, with additional aliases across the standard library.
const CAT_FOUND: bool = true;
fn main() {
let result: Result<(), String> = pet_cat();
match result {
Ok(_) => println!("Great, we could pet the cat!"),
Err(error) => println!("Oh no, we couldn't pet the cat: {error}")
}
}
fn pet_cat() -> Result<(), String> {
if CAT_FOUND {
Ok(())
} else {
Err(String::from("The cat is nowhere to be found!"))
}
}
Vlang
[edit]The Error type is an interface for iError.
const cat_found = true
fn main() {
cat_name := get_pet_cat_name() or {
println("Oh no, we couldn't pet the cat!")
exit(1)
}
println('Great, we could pet the cat ' + cat_name)
}
fn get_pet_cat_name() !string {
if cat_found { return 'Max' }
else { return error('the cat is nowhere to be found') }
}
See also
[edit]References
[edit]- ↑ "std::expected - cppreference.com". en.cppreference.com. 25 August 2023. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
- ↑ "Result · An Introduction to Elm". guide.elm-lang.org. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
- ↑ "Data.Either". hackage.haskell.org. 22 September 2023. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
- ↑ "Result - Kotlin Programming Language". kotlinlang.org. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
- ↑ "Error Handling · OCaml Tutorials". ocaml.org. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
- ↑ "std::result - Rust". doc.rust-lang.org. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
- ↑ "stdlib: Add result module · rust-lang/rust@c1092fb". github.com. 29 October 2011. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
- ↑ "Scala Standard Library 2.13.12 - scala.util.Either". www.scala-lang.org. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
- ↑ "Result | Apple Developer Documentation". developer.apple.com. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
- ↑ cppreference.com (19 August 2026). "std::unexpect_t, std::unexpect". cppreference.com. cppreference.com.
- ↑ cppreference.com (19 August 2026). "std::bad_expected_access". cppreference.com. cppreference.com.