日本語

Error Handling

LuneScript provides mechanisms for developing robust applications, ranging from simple error representation using nil to type-safe __Ret types and the "error delegation" feature for efficient handling.

__Ret<T, E> Type

__Ret<T, E> is an algebraic data type (ADT) used to represent a value upon success (Ok) and error information upon failure (Err) in a single type. It is equivalent to Rust's Result<T, E>.

// Conceptual internal definition
alge __Ret<T, E> {
    Ok( val: T ),
    Err( err: E ),
}

Basic Usage

Use .Ok(value) to return a value and .Err(error) to return an error. The receiving side can decompose it safely with a match statement.

fn divide( a: real, b: real ): __Ret<real, str> {
    if b == 0.0 {
        return .Err( "division by zero" );
    }
    return .Ok( a / b );
}

let result = divide( 10.0, 0.0 );
match result {
    case .Ok( val ) { print( "Success:", val ); }
    case .Err( msg ) { print( "Error:", msg ); }
}

__Er Type

When detailed information such as position information is needed as error info instead of a simple string, using the standard __Er type is recommended.

fn sub(): __Ret<int, __Er> {
    return .Err( __serr( "something went wrong" ) );
}

Error Delegation (! Operator)

When calling functions that may cause errors in succession, checking with match or if every time makes the logic hard to read. The ! operator automates this check.

Principle of Operation

When ! is appended to the end of an expression, the compiler behaves as if it generated the following code:

fn step1(): __Ret<int, str> { return .Ok(1); }
fn step2(val: int): __Ret<int, str> { return .Ok(val + 1); }

fn series(): __Ret<int, str> {
    // If step1() is Err, immediately return .Err(...)
    let res1 = step1()!; 
    
    // Same for step2(). If normal, res2 gets the value
    let res2 = step2( res1 )!;
    
    return .Ok( res2 );
}

Combining with Nilable

The ! operator can also be used with Nilable types (T!). In this case, the return value of the current function must also be Nilable.

fn getVal(): int! { return nil; }

fn process(): int! {
    let val = getVal()!; // If getVal() is nil, immediately return nil
    return val + 1;
}

Guidelines for Usage

Method Suitable Cases Features
Nilable (T!) Simple absence, or when error content is obvious. Most lightweight and convenient.
Multiple Returns (T!, str!) When prioritizing compatibility with common Lua styles. High Lua compatibility. Delegation with ! is possible.
__Ret<T, E> When you want to handle complex error information in a type-safe manner. Most robust. The state returned by the function is clear.
Using error delegation (!) allows you to write "Happy Path" processing into the main line, hiding exception handling behind the scenes. This dramatically improves the visibility of complex business logic.