Share to: share facebook share twitter share wa share telegram print page

Result type

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

  • 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++

The expected<T, E> class uses std::unexpected() to return the type E, and can return T directly.

import std;

using FileInputStream = std::ifstream;
using String = std::string;
using StringStream = std::stringstream;
using Path = std::filesystem::path;

enum class FileError {
    MissingFile,
    NoPermission,
    // more errors here
};

std::expected<String, FileError> loadConfig(const Path& p) noexcept {
    if (!std::filesystem::exists(p)) {
        return std::unexpected(FileError::MissingFile);
    }
    FileInputStream config{p};
    StringStream buffer;
    if (!config.is_open()) {
        return std::unexpected(FileError::NoPermission);
    }
    buffer << config.rdbuf();
    config.close();
    return buffer.str();
}

int main(int argc, char* argv[]) {
    Path p{/* some path here */};
    if (const std::expected<String, FileError> s = loadConfig(p); s.has_value()) {
        std::println("Config contents: {}", s.value());
    } else if (s.error() == FileError::MissingFile) {
        std::println("Error: path {} not valid or missing!", p);
    } else if (s.error() == FileError::NoPermission) {
        std::println("Error: no permission to read file at path {}!", p);
    } else {
        std::unreachable();
    }
}

Rust

The result object has the methods is_ok() and is_err().

const CAT_FOUND: bool = true;

fn main() {
    let result: Result<(), String> = pet_cat();
    if result.is_ok() {
        println!("Great, we could pet the cat!");
    } else {
        let error: String = result.unwrap_err();
        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

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

References

  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.
Kembali kehalaman sebelumnya