Edge Rewrite
// HTMLRewriter · presentation

This page was redesigned at the edge.

Cloudflare fetched the original article and streamed it through HTMLRewriter to apply an entirely new visual system without rebuilding the source page.

Jump to content

Result type

From Wikipedia, the free encyclopedia

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 Either type is used for this purpose, which is defined by the standard library as data Either a b = Left a | Right b, where a is the error type and b is 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 Result<R, E> similar to Rust Result<T, E>, and vavr includes an interface Either<L, R> similar to Haskell Either a b. Because Java and Kotlin are cross-compatible, Java can use the Result type from Kotlin.
  • In Kotlin, it is defined by the standard library as value class Result<out 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 enum Result<T, E> { Ok(T), Err(E) }.[6][7]
  • In Scala, the standard library also defines an Either type,[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 !T as the return type of a function. For example fn my_function() !string { ... }. Error Handling in V.

C++

[edit]

The 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();
        }
    }
}

Rust

[edit]

Enums in Rust are tagged unions, which can be unpacked with strong type checking through pattern matching.

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]
  1. "std::expected - cppreference.com". en.cppreference.com. 25 August 2023. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
  2. "Result · An Introduction to Elm". guide.elm-lang.org. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
  3. "Data.Either". hackage.haskell.org. 22 September 2023. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
  4. "Result - Kotlin Programming Language". kotlinlang.org. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
  5. "Error Handling · OCaml Tutorials". ocaml.org. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
  6. "std::result - Rust". doc.rust-lang.org. Archived from the original on 9 October 2023. Retrieved 9 October 2023.
  7. "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.
  8. "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.
  9. "Result | Apple Developer Documentation". developer.apple.com. Archived from the original on 9 October 2023. Retrieved 9 October 2023.