Result - Krystian-L-Lis/Stage GitHub Wiki

#Guide #Results

Overview

Rust programming language offers very neat error handling patterns. If a function can fail it returns a Result type, which then needs to be unwrapped using either if-let or match statement. This encourages explicit error handling.

fn main() {
    let input_1: &str = "1";
    let input_2: &str = "1000";
    let input_3: &str = "123";

    if let Ok(val) = input_1.parse::<i8>() {
        println!("Parsed: {}", val);
    }

    if let Err(err) = input_2.parse::<i8>() {
        println!("Error: {:?}", err);
    }

    match input_3.parse::<i8>() {
        Ok(val) => println!("Parsed: {}", val),
        Err(err) => println!("Error: {:?}", err),
    }
}

The point of Result, although limited compared to what Rust provides, is to deliver a lightweight system for communicating what caused a function or method to fail. It introduces some indirection, but this is limited to a few functions and DINT values. It also helps visually, or conceptually, distinguish when a method or function fails or succeeds. For example:

// Assuming the function returns Result
IF IsOk(FailableFunction()) THEN
    // Success
END_IF

IF IsErr(FailableFunction()) THEN
    // Failure
END_IF

CASE FailableFunction() THEN
    Ok:
        // Handle success
    None:
        // Handle absence of value
    Error:
        // Handle general error
    Err.Ovf:
        // Handle overflow error
    Err.Itf0:
        // Handle some specific error
    ELSE
        // Handle unexpected case
END_IF

This is easier to understand and maintain compared to the following:

// Assuming the function returns BOOL
IF FailableFunction() THEN
    // Success ? Fail ? Neither ?
END_IF

The difference should now be clear. Hopefully, this can be built into Structured Text by default in a more advanced Rust-like format.

Why not use an Enum? The answer is straightforward: Enums cannot be extended. The idea here is that the framework provides a few basic error variants, but users can define their own error variants depending on their needs.

Result

An alias over INT value. The idea is that any value larger than 0 means success or partial success, any value smaller than 0 means failure, and 0 itself means neither. This framework provides basic error values: Ok := 1, Error := -1, and None := 0. Slightly more advanced values are provided through the Err namespace:

    Itf0            : Result := -2; // Null Interface 
    Str0            : Result := -3; // Empty String
    ItfEq           : Result := -4; // Interfaces are equal
    NoMatch         : Result := -5; // No match
    Ptr0            : Result := -6; // Null Pointer
    InvRef          : Result := -7; // Invalid reference
    Ovf             : Result := -8; // Overflow/Out of bounds
    Udf             : Result := -9; // Undefined
    Idx             : Result := -10; // Index error
    TcLib           : Result := -11; // Error caused by TwinCAT libraries
    InfLoop         : Result := -12; // Potential infinity loop
    IncArg          : Result := -13; // Incorrect input argument
    Init            : Result := -14; // Initialization error
    NotFound	    : Result := -15; // Item not found
    InvItf          : Result := -16; // Invalid interface
    End             : Result := -17; // End of collection

Provides a way to convert Result values provided by the framework to String.

Result Functions

Multiple result functions are available. They take a Result value and return BOOL if the result matches what they check for.

These functions are:

  • IsOk - Check for success values.
  • IsErr - Check for failure values.
  • IsFail - Check for not Ok values.
  • IsNone - Check for None value.
  • IsSome - Check for either success or failure.
  • IsEnd - Checks for end of collection errors

The result functions take Result as input and optionally output the same result for further processing.

IF IsErr(Failable(), nOut => nResult) THEN
    DebugStr(ResultToStr(nResult));
END_IF

Note: None should be used for outcomes that are not covered by the programmer.

Case statement

To carry the result value into the CASE statement, use the following syntax:

CASE (nResult := Failable()) OF
    // Variants
END_CASE

< Previous | Home | Next >

⚠️ **GitHub.com Fallback** ⚠️