Error Handling

#load "std/"

There is no support for exceptions of any kind in BL, however, there are a few features in the language helping with error handling such as defer and multiple return values. In general, every possibly failing function should return an error state in case of failure containing an error code and some message describing the problem. This style is widely adopted by the standard library and may be used in the user code as well.

The error state is represented by the following data structure:

_Error :: struct {
    msg: string_view;
    code: s32;

Error :: *_Error;


div :: fn (a: s32, b: s32) (s32, Error) {
    if b == 0 {
        // Return error with message.
        return 0, error("Divide by zero '%/%'!", a, b);
    // Return result and OK state.
    return a / b, OK;

main :: fn () s32 {
    loop i := -5; i <= 5; i += 1 {
        result, error :: div(10, i);
        if error {
            print("Error: %.\n", error);
        } else {
            print("Result is %.\n", result);
    return 0;

As already mentioned, the defer statement may be helpful in situations where we need to free some memory or do any kind of resource cleanup before the failing function returns the error state.


Error :: *_Error



OK : Error = null

No error.



is_error :: fn (err: Error, code: s32) bool #inline

Check whether err is representing error code. Returns false when err is null.



error :: fn { 

Overloaded function setting up error state. Error state is global variable holding Error instance, error function sets desired values and return pointer to this global. That means the Error must be handled immediately after it's returned from failing function since every Error state points to the same memory.

Error creating does not require any HEAP memory alocations.


fn (code: s32) Error #inline
fn (format: string, args: ...) Error #inline
fn (code: s32, format: string, args: ...) Error #inline

Sets error state with code and formatted message.